Using apply-groups to insert policy in a predictable manner….

Recently I’ve been solving some interesting problems around how routing policy can be implemented. What I’ve been trying to do is have a way that enables me to quickly insert a policy at the start of a set of routing-policies on a BGP neighbor to stop sharing routes.

For those who are not aware, you can implement multiple policies in a chain on a BGP session. You do this like so;

[edit protocols bgp group R2]
[email protected]# show 
export [ policy-1 policy-2 policy-3 ];
neighbor 192.168.3.1 {
    peer-as 2;
}

In this configuration, all policies will be evaluated sequentially. Policy with matching terms will take action as defined in the policy on the routes matched. Routes will continue to be processed by subsequent terms in each policy until a terminating action is hit. A “terminating action” is something like an “accept” or “reject” action (once you hit one of these you use the actions gathered so far including the terminating action, then stop processing)

Let us say for the sake of this test that the policies we have applied to our peer do 2x as-path prepends, add a MED value, then accept all routes;

[edit policy-options]
[email protected]# show 
policy-statement policy-1 {
    then as-path-prepend "4 4";
}
policy-statement policy-2 {
    then {
        metric 400;
    }
}
policy-statement policy-3 {
    then accept;
}

This would result in the following routes being sent from this router (note the MED and as-path prepends);

[email protected]# run show route advertising-protocol bgp 192.168.3.1    

inet.0: 6 destinations, 6 routes (6 active, 0 holddown, 0 hidden)
  Prefix		  Nexthop	       MED     Lclpref    AS path
* 172.16.172.0/24         Self                 400                4 4 [4] I
* 192.168.3.0/24          Self                 400                4 4 [4] I
* 192.168.6.0/24          Self                 400                4 4 [4] I

In the scenario I described at the start, the aim was to be able to easily (with one line of configuration) insert a policy at the start of the policy-set that rejected all routes. However, as described above, this peer might have existing policies that allow routes to be sent.

Assume we say that I have already created the following policy;

[edit policy-options]
+   policy-statement policy-reject {
+       then reject;
+   }

If I quickly activated this by adding it as an export policy, it would appear as the last policy on the policy-chain;

[email protected]# set protocols bgp group R2 export policy-reject 

[edit]
[email protected]# show | compare 
[edit protocols bgp group R2]
-    export [ policy-1 policy-2 policy-3 ];
+    export [ policy-1 policy-2 policy-3 policy-reject ];

As we can see below, this does not reject any of the routes, because the reject action is processed after a terminating accept action in policy-3;

[email protected]# run show route advertising-protocol bgp 192.168.3.1              

inet.0: 6 destinations, 6 routes (6 active, 0 holddown, 0 hidden)
  Prefix		  Nexthop	       MED     Lclpref    AS path
* 172.16.172.0/24         Self                 400                4 4 [4] I
* 192.168.3.0/24          Self                 400                4 4 [4] I
* 192.168.6.0/24          Self                 400                4 4 [4] I

In order to implement this in the manner I want with this way of doing it, I would have to do the following to achieve it;

[edit protocols bgp group R2]
[email protected]# delete export 
[email protected]# set export policy-reject
[email protected]# set export policy-1
[email protected]# set export policy-2
[email protected]# set export policy-3

You could shorten this by using the “insert” functionality, however you are still requiring a re-ordering of policies as opposed to a one liner to activate this.

The trick I have come up to solve this is quite cool. I am adding a term to an existing policy with an apply-group;

[email protected]# show | compare 
[edit]
+ groups {
+     policy-reject {
+         policy-options {
+             policy-statement policy-1 {
+                 term reject-term {
+                     then reject;
+                 }
+             }
+         }
+     }
+ }

When we activate this apply-group, the term gets inserted into policy-1, which is already ordered to be applied prior to the terminating accept action in policy-3;

[email protected]# show | compare 
[edit]
+ apply-groups policy-reject;

We can see here that it is implemented in policy-1;

[edit policy-options policy-statement policy-1]
[email protected]# show | display inheritance 
##
## 'reject-term' was inherited from group 'policy-reject'
##
term reject-term {
    ##
    ## 'then' was inherited from group 'policy-reject'
    ## 'reject' was inherited from group 'policy-reject'
    ##
    then reject;
}
then as-path-prepend "4 4";

As policy-1 is already the first policy to be processed, this ensures that without having to re-order our existing policies we can insert a reject policy at the start. We can now check the result;

[email protected]# run show route advertising-protocol bgp 192.168.3.1    

[edit]
[email protected]#

And it is working!

You might ask why I did not just apply a new policy in an apply-group instead of a new term? The reason for this is that new policies are added at the end of the policy chain, while a new term in a pre-existing policy uses the existing place that policy has in the policy-chain.

For my purposes, this has enabled me to give out a one-line command which a large group of people can use to disable the advertisement of certain routes at certain times. As with everything in Junos though, there are many possible uses for this set of functionality. Hope this helps!

3 thoughts on “Using apply-groups to insert policy in a predictable manner….

  1. You know about “insert” in the Juniper CLI, right? That allows you to move a statement that you’ve just added which it inconsiderately placed at the end to a more useful location? (See, eg, Juniper examples: http://www.juniper.net/techpubs/en_US/junos13.3/topics/example/junos-software-configuration-new-indentifier-including.html)

    So your delete/set again can be written:

    edit protocols bgp group R2
    set export policy-reject
    insert export policy-reject before policy-1

    (or “insert export policy-reject before policy-3”)

    Granted that’s still two lines, rather than one. But it’s helpful in many places in the Juniper config where ordering matters.

    You may also want to consider a community tag which translates into, eg, “no export from here”, and then leave that part of the policy permanently at the start. Or possibly have a policy at the start which is just “then next” normally but you can set to “then reject” to make it shut up immediately. Or even one policy that combines both of those (“if no export community then reject else default then next” — where you can change the “then next” to “then reject” as a one line change.)

    Ewen

    PS: I hope you don’t really name your policies “policy-1”, “policy-2”, etc. “prepend-two”, “med-400” and “accept” would be much more readable 🙂

    • Hey Ewen,

      Yup – sure do, and I have actually added a reference to that (after a couple of people have commented this), however it depends what you are trying to achieve. If you are wanting net-eng guys who know this stuff backwards to do it, then that’s absolutely valid. However it’s more difficult to have who do not spend as much time dealing with the Junos CLI order policy correctly and get it right every single time.

      I’m not saying that this is the perfect solution for most (or even many at all) scenarios, just another useful tool I thought of that was relevant to my use case :).

      With regards to doing this with communities – yes totally agree. Again it depends on what you were trying to achieve. This was a quick hack to achieve something that I needed to do with a specific goal. One of the goals was that it was a one liner which did not require any reordering of policy. This was where this seems like a good solution.

      But yeah – just one tool in the toolbox.

      And yes – policy-names were just whipped up on the fly to demonstrate my example, not for the purposes of anything you would want on a production network :).

      Cheers for commenting – you make good points.

      –hoff

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s