11.4 DIET Policies


Earlier in the chapter we observed the similarity between a policy and a computer program. This concept will now be explored further by applying a few computer program design rules. The first rule is that there are many ways to design, or write, a computer program. Likewise, there are many different methods of policy composition. Often, if the syntax is correct and the program or policy works, then you have achieved your goal. However, often elements of simplicity and performance tend to fall by the wayside. It is important to design our policies in the most modular, scalable, and efficient fashion possible. This makes our policies easier to parse, configure, and interpret.

We propose calling this the DIET policy design method. You may ask how this name was determined. Seeing as how the fellow playing at being our manager while writing this book could stand to lose a few pounds , it was decided that the idea of shedding excess weight could apply to policy as well. If you chuckled when you read this, then the likelihood is that you will remember the four steps of policy dieting when needed and that you also had "one of those" kinds of managers! The four steps of the DIET are outlined in Figure 11-6.

Figure 11-6. DIET Policy Design Model

graphics/11fig06.gif

The four steps of the DIET policy method that will aid in proper design and implementation of an effective policy are as follows :

  1. Design First, follow a set of specialized policy design rules to create an effective routing policy.

  2. Implement After applying good design practice, the policy must then be put to work. Implementing the policy in JUNOS is key at this point. Though the policy has been configured, it has not yet been assigned to a routing protocol or activated.

  3. Execute Policy execution is the act of activating the policy by applying it to a specific routing policy.

  4. Test The testing stage is the last phase. It is always good idea to verify that the policy functions as intended.

In the next section you will begin your policy creation using the DIET methodology. The objective will be to design polices that are easy to understand and implement and that carry out the functions defined in the design stage.

11.4.1 Designing Policies

The world of computer programming has given us subroutines. Subroutines are a way of breaking down a complex problem into smaller pieces so that each section can solve a subset of the overall problem, leading to a solution that is easy to implement and understand. There are many reasons to break down a program into subroutines. Consider the following from an online Perl programming guide by Emmie Lewis [13]:

  • Reduce complexityEach subroutine represents a building block of the overall solution.

  • Facilitate modificationFuture modification is easier if a program is divided into subroutines.

  • Hide orderSubroutines can be used to hide the order in which a program processes.

  • Improve performanceThere are fewer lines to compile and execute.

  • Hide complex detailPrograms are easier to read and understand.

  • Reuse parts of codeOnce a subroutine is defined, it can be reused anywhere .

Now here's the same text again, but with the word "program" replaced with "policy" and the word "subroutine" with " term ":

  • Reduce complexityEach term represents a building block of the overall solution.

  • Facilitate modificationFuture modification is easier if a policy is divided into terms.

  • Hide orderTerms can be used to hide the order in which a policy processes.

  • Improve performanceThere are fewer lines to compile and execute.

  • Hide complex detailPolicies are easier to read and understand.

  • Reuse parts of codeOnce a policy is defined, it can be reused anywhere.

The essence of good policy design is taking a policy you want to design and separating it into as many terms as there are tasks .

There are also similarities between the if , then , and else statements used in programming and the from , to , and then statements used in policy. The if statement represents the match conditions of the from and to statement. The then statement is executed if the from and to statements match, and the else statement represents the default policy action for all routes that did not match.

For example, to define a policy that selects all OSPF routes from the routing table learned from a particular neighbor ( 10.0.1.1 ) and sets them to a metric of 10, the code could look as follows:

 policy-options {      policy-statement get-ospf {         from {             protocol ospf;             neighbor 10.0.1.1;         }         then {             metric 10;             accept;         }     } } 

Using the DIET methodology, the objectives of the policy were divided into two tasks:

  1. Look at OSPF routes only; ignore all other routes, such as BGP.

  2. From the OSPF routes, select only the routes originating from neighbor 10.0.1.1 and set their metric to 10.

Most of simple policies are designed with a single term. A single-term policy contains only one term. However, a term does not need to be explicitly specified in the policy. In the following example, we see a policy named redistribute-isis with one term, get-isis . The get-isis term matches and accepts all IS-IS routes in the routing table.

 policy-statement redistribute-isis {      term get-isis {         from protocol isis;         then accept;     } } 

This policy can be rewritten without a term statement as follows:

 policy-statement redistribute-isis {      from protocol isis;     then accept; } 

Both policies have the exact same effect. The only difference between the two is that the explicit term definition was dropped in the second example. The policy is called redistribute-isis and contains two statements. The from protocol isis statement selects all IS-IS routes, which are in turn accepted with the accept statement.

The second example may seem like good practice, and in some cases it is. However, it is recommended to keep the explicit term definition, which is more in line with the scalability rule defined earlier. There is an old saying that a stitch in time saves nine. That saying can be applied here. If you must modify a single-term policy at a later stage, then having spent an extra few seconds on explicitly defining a term makes the policy easier to modify and scale. This is not so much a rule as a recommendation. At the end of the day, a policy will wear the mark of its designer. The recommended design rules can be summed up as follows:

  • Work out where you need policy and why.

  • Decide on how many policies are required.

  • Decide on how many terms are needed in each policy and include at least one for scalability.

  • Name each term and policy appropriately.

  • Implement the policy as you have defined it.

11.4.2 Implementing Policies

After a policy has been designed, the next step is to implement it. All policies are implemented in the CLI under the [edit policy-options] level of the hierarchy. There are a number of commands used to implement a policy. A typical implementation could take the following three steps:

  1. Assuming you are at the [edit] level of the CLI hierarchy, then enter the edit policy-options policy-statement policy-name command, policy-1 being the chosen name of the policy. This will place you at the [edit policy-options policy-statement policy-1] hierarchy level like so:

     [edit]  user@Chicago# edit policy-options policy-statement policy-1 [edit policy-options policy-statement policy-1] user@Chicago# 

    Terms can then be implemented within the policy. Under each term, match conditions are created using from and to statements, while match actions are created using the then statement. Possible match actions and match conditions have been described earlier in the chapter.

    Terms are created with match actions and match conditions. Match conditions for the from statement are created using the set term term-name from match-condition command, where match-condition matches one of the conditions observed earlier in the chapter, and term-1 is the chosen name of the term. For example:

     [edit policy-options policy-statement policy-1]  user@Chicago# set term term-1  from protocol ospf  [edit policy-options policy-statement policy-1] user@Chicago# show term term-1 {  from protocol ospf;  } 

    The same concept applies to the to statement using a valid match condition described previously in this chapter. For example:

     [edit policy-options policy-statement policy-1]  user@Chicago# set term term-1 to neighbor 10.0.0.1 [edit policy-options policy-statement policy-1] user@Chicago# show term term-1 {     from protocol ospf;  to neighbor 10.0.0.1;  } 

    Match actions for the then statement are created using the set term term-name then match-action command, where match-action matches one of the possible actions described earlier in the chapter. For example:

     [edit policy-options policy-statement policy-1]  user@Chicago# set term term-1  then accept  [edit policy-options policy-statement policy-1] user@Chicago# show term term-1 {     from protocol ospf;     to neighbor 10.0.0.1;  then accept;  } 
  2. Next, the second term can be implemented, and so on, to create the policy chain, as shown below:

     [edit policy-options policy-statement policy-1]  user@Chicago# set term term-2 from protocol bgp [edit policy-options policy-statement policy-1] user@Chicago# set term term-2 to neighbor 10.0.0.2 [edit policy-options policy-statement policy-1] user@Chicago# set term term-2 then metric 20 [edit policy-options policy-statement policy-1] user@Chicago# set term term-2 then accept [edit policy-options policy-statement policy-1] user@Chicago# show term term-1 {     from protocol bgp;     to neighbor 10.0.0.1;     then accept; } term term-2 {     from protocol bgp;     to neighbor 10.0.0.2;     then {         metric 10;         accept;     } } 
  3. Lastly, it is a good idea to implement a default action term that contains only a then reject or then accept statement. This catches everything that did not match the other terms and ensures that the final action is not being left to system defaults. This final term is implemented using the set term finalterm then reject statement, which leaves us with a complete policy as shown below:

     [edit policy-options policy-statement policy-1]  user@Chicago# set term finalterm  then reject  [edit policy-options policy-statement policy-1] user@Chicago# show term term-1 {     from protocol ospf;     to neighbor 10.0.0.1;     then accept; } term term-2 {     from protocol bgp;     to neighbor 10.0.0.2;     then {         metric 10;         accept;     } } term finalterm {  then reject;  } 

The order in which policies are implemented under the [edit policy-options] hierarchy level does not matter; it is the order of their execution that is important. The order in which terms are defined within a policy is also important. Whenever the active configuration is being compiled by the routing engine, policies are read in the order in which they are applied. Terms, however, are read from top to bottom (see Figure 11-5). Policies are executed term by term from top to bottom unless another policy is called within a term.

There are two other methods of policy implementation that we have not mentioned yet. These include route filters and regular expressions. Both are very important areas of policy implementation and will be covered in detail in subsequent sections.

11.4.3 Executing Policies

Policies do not automatically take effect after implementation. Rather, they are executed after they are applied to the appropriate routing protocol, such as RIP, IS-IS, OSPF, BGP, or Distance Vector Multicast Routing Protocol (DVMRP). Earlier in the chapter we reviewed import and export policies. At this stage we must set the rules for policy application. The primary rule is that we cannot set an import policy for IS-IS or OSPF, which would be detrimental to routing stability. We can, however, set up import and export policies for BGP. A policy is executed using the set protocols command under the [edit] hierarchy level of the CLI. Let us suppose that we have two other export policies, namely policy-2 and policy-3 , to apply under the BGP hierarchy level. This would appear in the configuration as follows:

 [edit]  user@Chicago#  set protocols bgp export [policy-1 policy-2 policy-3]  Extract from bgp configuration: protocols {     bgp {  export [ policy-1 policy-2 policy-3 ];  } 

Order is very important here because we are creating a policy chain. Our chain is made up of three policies. First policy-1 is evaluated and only if there are no matches in policy-1 , policy-2 is evaluated. Again, if there are no matches in policy-2 , policy-3 is evaluated as the last step. The policy chain is read by the router from left to right and is treated as an ordered list. Thus, policy-1 is applied and executed first, and so forth. The insert command can be used to change the order in which policies are evaluated and has two options: before and after . The following example illustrates its use:

 [edit]  user@Chicago# show protocols bgp export [ policy-1 policy-2 policy-3 ]; [edit] user@Chicago# insert protocols bgp export policy-2 before policy-1 [edit] user@Chicago# show protocols bgp export [ policy-2 policy-1 policy-3 ]; [edit] user@Chicago# insert protocols bgp export policy-2 after policy-3 [edit] user@Chicago# show protocols bgp export [ policy-1 policy-3 policy-2 ]; 

In the above example we have modified the order in which the policies are executed by moving around policy-2 .

Within BGP, import and export policies can be applied at three different levels:

  1. Global level under the [edit protocols bgp] hierarchy level

  2. Group level under the [edit protocols bgp group groupname ] hierarchy level, where groupname is the name of the BGP group

  3. Neighbor level under the [edit protocols bgp group groupname neighbor neighbor-address ] hierarchy level, where neighbor-address is the address of the specific BGP neighbor that the policy applies to

The general rule is that neighbor-level policies supercede group-level policies, and group-level policies take precedence over global-level policies.

The next example shows a BGP configuration that includes two BGP peer groups, one for internal and one for external peers. For the purpose of this example, we have specifically used private addresses and ASNs. It is important to note that external peer addresses would usually be public addresses, that is addresses other that those reserved for private use as specified in RFC 1918 [6]. There are three policies configured as follows:

  1. global-bgp-policy only applies to the internal-peers group since the external-peers group contains its own group policy, which overrides the global policy

  2. group-policy only applies to neighbors 192.168.1.2 and 192.168.1.3 as neighbor 192.168.1.1 contains its own policy, which overrides the group and global policies

  3. special-policy only applies to neighbor 192.168.1.1 in the external-peers group and overrides both group and global policies

 [edit]  user@Chicago# show protocols bgp  export global-bgp-policy;  group external-peers {     type external;  export group-policy;  peer-as 65535;     neighbor 192.168.1.1 {  export special-policy;  }     neighbor 192.168.1.2;     neighbor 192.168.1.3; } group internal-peers {     type internal;     neighbor 172.16.1.1;     neighbor 172.16.1.2; } 

11.4.4 Testing Policies

After your policies have been designed, implemented, and executed, you are nearly finished with your policy DIET! The last step is to test the policies. Aside from actual use and implementation, policies can be router tested in two ways:

  1. Against a specific route using the test policy policy-1 a.b.c.d/e command

  2. Against the entire unicast routing table inet.0 using the test policy policy-1 0.0.0.0/0 command

In the above commands, policy-1 is the name of the policy being tested, a.b.c.d/e is a specific route being tested, and 0.0.0.0/0 signifies all the routes contained in the inet.0 routing table.

Through the use of the test policy command, it is possible to determine whether or not the policy implemented meets the intended design criteria. Consider the simple network in Figure 11-7, which shows three routers: Washington D.C., Chicago, and San Francisco. All routers are running OSPF and belong to backbone area 0 . The 172.16 . x /24 networks are static routes used to simulate attached customer networks. Table 11-7 lists the aggregate required on each router to encompass each of the static routes.

Figure 11-7. Simple Network to Illustrate Policy Testing

graphics/11fig07.gif

Table 11-7. Aggregate Routes
Router Aggregate
Washington D.C 172.16.0.0/22
Chicago 172.16.4.0/22
San Francisco 172.16.8.0/22

The network is set up so that the aggregates are shared into OSPF through use of policy, while the specific networks are not. This is achieved by means of a simple export policy named aggregate-2-ospf . The aggregate routes will be accepted by this policy, while everything else will be rejected. As you review the configurations, notice that each policy is applied as an export statement within OSPF before the actual policy is listed. The relevant pieces of the configuration have been highlighted for you. Following are the configurations for each of the three routers.

  1. Router Washington D.C. configuration:

     [edit]  user@Chicago# show version 5.0R1.4; system {     host-name DC;     root-authentication {         encrypted-password "$yqlMb$pgnl6m0eYT/pAIa7bENbl/"; # SECRET-DATA     }     login {        user lab {         uid 2000;          class superuser;           authentication {            encrypted-password "$er32.$ZLaup5gYipIjmWcUmBMEr0"; # SECRET-DATA             }         }     }     syslog {         user * {             any emergency;         }         file messages {             any notice;             authorization info;         }     } } interfaces {     so-1/0/0 {         unit 0 {             family inet {                 address 192.168.10.1/30;             }         }     }     so-1/0/1 {         unit 0 {             family inet {                 address 192.168.30.2/30;             }         }     } } routing-options {     static {         route 172.16.1.0/24 receive;         route 172.16.2.0/24 receive;         route 172.16.0.0/24 receive;         route 172.16.3.0/24 receive;     }     aggregate {         route 172.16.0.0/22;     } } protocols {     ospf {  export aggregate-2-ospf;  area 0.0.0.0 {             interface all;         }     } }  policy-options {   policy-statement aggregate-2-ospf {   term match-aggregate {   from protocol aggregate;   then accept;   }   term reject-all-else {   then reject;  }     } } 
  2. Router Chicago configuration:

     [edit]  lab@Chicago# show version 5.0R1.4; system {     host-name Chicago;     root-authentication {         encrypted-password "$a99Mb$PBmrtU.60ftgPmFQVSeKU/"; # SECRET- DATA     }     login {       user lab {         uid 2000;          class superuser;           authentication {            encrypted-password "$i5Z2.$XHJgtMPiz7gqFHjOQUma9/"; # SECRET-DATA             }         }     }     syslog {         user * {             any emergency;         }         file messages {             any notice;             authorization info;         }     } } interfaces {     so-2/0/0 {         unit 0 {             family inet {                 address 192.168.10.2/30;             }         }     }     so-2/0/1{         unit 0 {             family inet {                 address 192.168.20.1/30;             }         }     } } routing-options {     static {         route 172.16.4.0/24 receive;         route 172.16.5.0/24 receive;         route 172.16.6.0/24 receive;         route 172.16.7.0/24 receive;     }     aggregate {         route 172.16.4.0/22;     } } protocols {     ospf {  export aggregate-2-ospf;  area 0.0.0.0 {             interface all;         }     } }  policy-options {   policy-statement aggregate-2-ospf {   term match-aggregate {   from protocol aggregate;   then accept;   }   term reject-all-else {   then reject;  }     } } 
  3. Router San Francisco configuration:

     [edit]  lab@SanFran# show version 4.4R3.4; system {     host-name SanFran;     root-authentication {         encrypted-password "$w5MMb$bA04r6A7VAEMOwKs3Fa0l0"; # SECRET- DATA     }     login {        user lab {         uid 2000;          class superuser;           authentication {            encrypted-password "nPMb$Gfjes5RfwJh8zBNYR45rk1"; # SECRET-DATA             }         }     }     syslog {         user * {             any emergency;         }         file messages {             any notice;             authorization info;         }     } } interfaces {     so-1/2/0 {         unit 0 {             family inet {                 address 192.168.30.1/30;             }         }     }     so-1/2/1 {         unit 0 {             family inet {                 address 192.168.20.2/30;             }         }     } } routing-options {     static {         route 172.16.8.0/24 receive;         route 172.16.9.0/24 receive;         route 172.16.10.0/24 receive;         route 172.16.11.0/24 receive;     }     aggregate {         route 172.16.8.0/22;     } } protocols {     ospf {  export aggregate-2-ospf;  area 0.0.0.0 {             interface all;         }     } }  policy-options {   policy-statement aggregate-2-ospf {   term match-aggregate {   from protocol aggregate;   then accept;   }   term reject-all-else {   then reject;  }     } 

You can test the effect of the policies by issuing the show policy command on any of the three routers in the example. As previously described, there are two ways of using the test policy command: testing against the entire routing table or against a specific route. The following example uses the Washington D.C. router to test aggregate-2-ospf against the aggregate route 172.16.0.0/22 and against all routes in the routing table. The output is as follows:

 user@Chicago> test policy aggregate-2-ospf 172.16.0.0/22  inet.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden) Prefixes passing policy: 172.16.0.0/22      *[Aggregate/130] 03:34:06    Reject Policy aggregate-2-ospf: 1 prefix accepted, 4 prefixes rejected 

The sample output confirms that the aggregate route passes the policy, but how can we be sure that no other routes will match? You should also issue a test policy 0.0.0.0/0 command, as follows, to ensure that no unexpected routes slip through the policy:

 user@Chicago> test policy aggregate-2-ospf 0.0.0.0/0  inet.0: 13 destinations, 13 routes (13 active, 0 holddown, 0 hidden) Prefixes passing policy: 172.16.0.0/22      *[Aggregate/130] 03:51:24                      Reject Policy aggregate-2-ospf: 1 prefix accepted, 12 prefixes rejected 

As you can see, the results are very similar to the previous output, which in this case is a good sign. Washington D.C.'s routing table contains 13 active routes, but only the aggregate passed the policy, which is exactly what it was designed for.

Another useful command, the show policy command, lists all configured policies on a router.

 user@Chicago> show policy  Configured policies: Aggregate-2-ospf 

In the previous example, there is only one policy configured on the router. If you would like to see what is configured in a policy, you can issue the show policy policy-name command, where policy-name is the name of the policy you are examining. Issuing the show policy aggregate-2-ospf command shows the rules defined within the policy as follows:

 user@Chicago> show policy aggregate-2-ospf  Policy aggregate-2-ospf:     Term match-aggregate:         from proto Aggregate         then accept     Term reject-all-else:         then reject 


Juniper Networks Reference Guide. JUNOS Routing, Configuration, and Architecture
Juniper Networks Reference Guide: JUNOS Routing, Configuration, and Architecture: JUNOS Routing, Configuration, and Architecture
ISBN: 0201775921
EAN: 2147483647
Year: 2002
Pages: 176

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net