The issue I was facing is how to create route policy in JunOS that can both be used directly (export/import from BGP group/neighbor), and as a subroutine from another policy which needs to add more specialized filtering criteria to those coded in the subroutine.
Because I found the JunOS documentation and examples not as helpful as I hoped, I decided to share my learnings with the form, in hope to help other people looking for a similar solution. I will also show how to test such filtering policies to validate their logic is consistent with the intent.
The key difficulty in achieving our objective was the lack of an "else" clause in the "policy-statement" flow control, which would allow an explicit "reject" when the subroutine returns FALSE. However, since the route policy (unlike most programming languages) does not have an "if/then/else" flow control structure, only an "if/then", another way was required. We have learned that the "from <policy-name>" statement supports boolean logic, the solution presented itself - by applying a boolean not operator to the subroutine call, we can add an explicit "then reject" to discard the route entry consistently with the subroutine logic.
In the following example, the policy named "TEST" will reject all packets from certain prefixes when called directly from BGP, and when called from another policy will return FALSE for every prefix that ought to be rejected. To illustrate the later, we create a policy named "TEST-MAIN" which calls the former, and result in the same action as the subroutine itself, this performing consistently in both use cases.
With regards to testing, the point worth emphasizing is that the "test policy" command does not apply the policy to the prefix supplied as the argument, but rather will search the RIB for all route entries matching the prefix specified in the command, and apply the policy to those RIB entries. The presumed rationale for this is that policies act not just on the IP CIDR but also on the source protocol, community labels, AS paths etc, and it would awkward to permit all these attributes to be input in the command line.
The output of the "test policy" command indicates the number of rejected RIB entries, and both the count and the value of those RIB entries the policy has accepted.
# Define subroutine policy that can be used directly as well
set policy-options policy-statement TEST term 1 from route-filter 1.1.1.1/32 exact
set policy-options policy-statement TEST term 1 then reject
set policy-options policy-statement TEST then accept
# define a main policy calling the subroutine
set policy-options policy-statement TEST-MAIN term 1 from policy ( ! TEST )
set policy-options policy-statement TEST-MAIN term 1 then reject
set policy-options policy-statement TEST-MAIN then accept
# Populate RIB with test prefixes
set routing-options static route 1.0.0.0/8 reject
set routing-options static route 1.1.1.1/32 reject
set routing-options static route 1.1.1.2/32 reject
# Test the subroutine policy directly
lrosenboim@lab-cr02> test policy TEST 1.1.1.1/32
Policy TEST: 0 prefix accepted, 1 prefix rejected
lrosenboim@lab-cr02> test policy TEST 1.1.1.2/32
inet.0: 5 destinations, 5 routes (3 active, 0 holddown, 2 hidden)
+ = Active Route, - = Last Active, * = Both
1.1.1.2/32 *[Static/5] 00:03:25
Reject
Policy TEST: 1 prefix accepted, 0 prefix rejected
lrosenboim@lab-cr02> test policy TEST 1.0.0.0/8
inet.0: 5 destinations, 5 routes (3 active, 0 holddown, 2 hidden)
+ = Active Route, - = Last Active, * = Both
1.0.0.0/8 *[Static/5] 00:05:22
Reject
1.1.1.2/32 *[Static/5] 00:03:51
Reject
Policy TEST: 2 prefix accepted, 1 prefix rejected
# Test main policy
lrosenboim@lab-cr02> test policy TEST-MAIN 1.1.1.1/32
Policy TEST-MAIN: 0 prefix accepted, 1 prefix rejected
lrosenboim@lab-cr02> test policy TEST-MAIN 1.1.1.2/32
inet.0: 5 destinations, 5 routes (3 active, 0 holddown, 2 hidden)
+ = Active Route, - = Last Active, * = Both
1.1.1.2/32 *[Static/5] 00:05:41
Reject
Policy TEST-MAIN: 1 prefix accepted, 0 prefix rejected
lrosenboim@lab-cr02> test policy TEST-MAIN 1.0.0.0/8
inet.0: 5 destinations, 5 routes (3 active, 0 holddown, 2 hidden)
+ = Active Route, - = Last Active, * = Both
1.0.0.0/8 *[Static/5] 00:07:25
Reject
1.1.1.2/32 *[Static/5] 00:05:54
Reject
Policy TEST-MAIN: 2 prefix accepted, 1 prefix rejected
------------------------------
LEONID ROSENBOIM
------------------------------