InfraRunBook
    Back to articles

    Juniper BGP Configuration with Route Policy

    Juniper
    Published: Apr 21, 2026
    Updated: Apr 21, 2026

    A hands-on guide to configuring Juniper BGP sessions with route policies — covering prefix lists, community tagging, import and export policy construction, and verification commands.

    Juniper BGP Configuration with Route Policy

    Prerequisites

    Before diving in, you need a few things in place. I'm assuming you have a Juniper router running JunOS — this guide was written against JunOS 21.x but applies equally to 18.x and later releases. You'll need SSH access to the device and enough privilege to commit configuration changes, typically the

    super-user
    login class or a custom class with the
    configure
    permission.

    On the networking side, you need at least one established BGP session or the intent to bring one up. The examples here use two eBGP peers: one upstream provider and one downstream customer. You'll also want a clear picture of what you're trying to accomplish with route policy before you write a single term. Going into BGP policy work without a plan is how you end up leaking your entire routing table at 2 AM.

    Specific requirements going in:

    • JunOS 18.1 or later
    • At least one configured BGP neighbor with an established or pending session
    • Understanding of basic BGP concepts: AS numbers, NLRI, next-hop, MED, local preference
    • Familiarity with the Junos commit model — policy changes don't take effect until you commit

    Understanding Juniper Route Policies

    Juniper's route policy model is genuinely elegant once it clicks. Policies live under

    policy-options
    and are composed of terms. Each term has a
    from
    block for matching conditions and a
    then
    block for actions. Terms are evaluated top to bottom, and the first match wins. If no term matches, the implicit default action kicks in — and that default depends on where and how the policy is applied.

    This is different from Cisco's route-maps, and I've seen engineers get bitten by the difference repeatedly. In JunOS, an import policy applied to an eBGP session has an implicit reject-all at the end. An export policy also implicitly rejects everything unless you explicitly accept. That last point trips people up constantly — you build a perfectly valid policy that matches routes and tags them with communities, forget the final

    then accept
    term, and nothing gets advertised. The router isn't broken. Your policy is just doing exactly what you told it to.

    Policies can reference three types of reusable building blocks: prefix lists defined under

    policy-options prefix-list
    , AS-path regular expressions under
    policy-options as-path
    , and BGP communities under
    policy-options community
    . You can also reference other policies by name using
    from policy
    inside a term, which lets you build modular, composable policy logic as your network grows in complexity.

    Step-by-Step BGP Configuration

    Step 1: Define Prefix Lists

    Start by building your prefix lists. These are reusable objects that policy terms reference by name. I always define these first because it forces you to think concretely about which networks you actually want to permit or deny before writing a single policy term. Skipping this step and writing inline prefix-list-filter entries scattered through your policy makes long-term maintenance painful.

    set policy-options prefix-list CUSTOMER-PREFIXES 172.16.10.0/24
    set policy-options prefix-list CUSTOMER-PREFIXES 172.16.20.0/24
    set policy-options prefix-list CUSTOMER-PREFIXES 172.16.30.0/24
    
    set policy-options prefix-list INTERNAL-LOOPBACKS 10.0.0.0/24
    
    set policy-options prefix-list DEFAULT-ROUTE 0.0.0.0/0

    The

    CUSTOMER-PREFIXES
    list contains networks we're advertising to our upstream provider.
    INTERNAL-LOOPBACKS
    covers loopback addresses we want reachable externally for management.
    DEFAULT-ROUTE
    is used in import policy to explicitly accept the default if our provider sends it — and to set specific treatment on it.

    Step 2: Create AS-Path Regular Expressions

    AS-path filters let you match routes based on the AS path attribute. JunOS uses POSIX-style regex here, which is more powerful than what you get on other platforms but does require you to actually know regex. A few patterns that cover most real-world scenarios:

    set policy-options as-path PEER-ORIGINATED "^65002$"
    set policy-options as-path CUSTOMER-AS "^65003$"
    set policy-options as-path ANY-AS ".*"
    set policy-options as-path TRANSIT-THROUGH-PEER ".* 65002 .*"

    PEER-ORIGINATED
    matches only routes that originated directly from AS 65002 — the
    ^
    and
    $
    anchors mean the path must contain exactly that AS and nothing else.
    TRANSIT-THROUGH-PEER
    would match any route where AS 65002 appears anywhere in the path, regardless of what else surrounds it. Use the anchored form when you want to accept only customer-originated routes, not routes that merely transited through them.

    Step 3: Configure BGP Communities

    Communities are how you tag routes with metadata that carries policy intent. They're invaluable for signaling routing decisions across peering boundaries and for implementing tiered treatment based on route origin. Define the communities you'll use before writing policy terms that reference them:

    set policy-options community UPSTREAM-PEER members 65001:100
    set policy-options community CUSTOMER-ROUTE members 65001:200
    set policy-options community LOCAL-PREF-HIGH members 65001:300
    set policy-options community BLACKHOLE members 65001:666
    set policy-options community NO-EXPORT members no-export

    The

    no-export
    well-known community is built into JunOS — you don't need to spell out the numeric value 65535:65281. The others use the standard
    ASN:value
    format. I use the local AS as the first octet so it's immediately clear which communities originate from my network versus communities sent by peers.

    Step 4: Build the Route Policy

    Now for the actual policy. Let's build both an import and export policy. The import policy controls what we accept from peers and how we treat it locally. The export policy controls what we advertise outbound.

    Import policy for our upstream provider peer in AS 65002:

    set policy-options policy-statement IMPORT-FROM-UPSTREAM term ACCEPT-DEFAULT from prefix-list DEFAULT-ROUTE
    set policy-options policy-statement IMPORT-FROM-UPSTREAM term ACCEPT-DEFAULT then local-preference 150
    set policy-options policy-statement IMPORT-FROM-UPSTREAM term ACCEPT-DEFAULT then community add UPSTREAM-PEER
    set policy-options policy-statement IMPORT-FROM-UPSTREAM term ACCEPT-DEFAULT then accept
    
    set policy-options policy-statement IMPORT-FROM-UPSTREAM term REJECT-RFC1918-10 from prefix-list-filter 10.0.0.0/8 orlonger
    set policy-options policy-statement IMPORT-FROM-UPSTREAM term REJECT-RFC1918-10 then reject
    
    set policy-options policy-statement IMPORT-FROM-UPSTREAM term REJECT-RFC1918-172 from prefix-list-filter 172.16.0.0/12 orlonger
    set policy-options policy-statement IMPORT-FROM-UPSTREAM term REJECT-RFC1918-172 then reject
    
    set policy-options policy-statement IMPORT-FROM-UPSTREAM term REJECT-RFC1918-192 from prefix-list-filter 192.168.0.0/16 orlonger
    set policy-options policy-statement IMPORT-FROM-UPSTREAM term REJECT-RFC1918-192 then reject
    
    set policy-options policy-statement IMPORT-FROM-UPSTREAM term ACCEPT-REMAINDER then accept

    A few things worth noting. The bogon filter terms use inline

    prefix-list-filter
    with the
    orlonger
    qualifier — this filters RFC 1918 space arriving from your upstream, which any responsible operator should do. In my experience, you'd be surprised how often providers accidentally leak private address space into eBGP sessions if you're not filtering it on your end. The final
    ACCEPT-REMAINDER
    term with no
    from
    conditions acts as a catch-all accept. Without it, anything that didn't match the earlier terms would hit the implicit reject at the end of the policy.

    Now the export policy for the same upstream peer:

    set policy-options policy-statement EXPORT-TO-UPSTREAM term ADVERTISE-CUSTOMER from prefix-list CUSTOMER-PREFIXES
    set policy-options policy-statement EXPORT-TO-UPSTREAM term ADVERTISE-CUSTOMER then community set CUSTOMER-ROUTE
    set policy-options policy-statement EXPORT-TO-UPSTREAM term ADVERTISE-CUSTOMER then accept
    
    set policy-options policy-statement EXPORT-TO-UPSTREAM term ADVERTISE-LOOPBACKS from prefix-list INTERNAL-LOOPBACKS
    set policy-options policy-statement EXPORT-TO-UPSTREAM term ADVERTISE-LOOPBACKS then accept
    
    set policy-options policy-statement EXPORT-TO-UPSTREAM term REJECT-EVERYTHING then reject

    This policy explicitly advertises customer prefixes and internal loopbacks, tags customer routes with a community, and rejects everything else. That final explicit reject isn't strictly necessary since the implicit default does the same thing for export, but I like being explicit — it makes intent obvious when someone reads the config six months from now.

    Step 5: Apply Policies to BGP

    Policies are useless until they're applied to BGP neighbors. Apply them at the group level when multiple peers share the same policy logic, or at the neighbor level for per-peer customization that overrides the group setting:

    set protocols bgp local-as 65001
    set protocols bgp group UPSTREAM-PROVIDERS type external
    set protocols bgp group UPSTREAM-PROVIDERS import IMPORT-FROM-UPSTREAM
    set protocols bgp group UPSTREAM-PROVIDERS export EXPORT-TO-UPSTREAM
    set protocols bgp group UPSTREAM-PROVIDERS neighbor 192.168.1.2 peer-as 65002
    set protocols bgp group UPSTREAM-PROVIDERS neighbor 192.168.1.2 description "Upstream Provider - AS65002"
    
    set protocols bgp group CUSTOMER-PEERS type external
    set protocols bgp group CUSTOMER-PEERS import IMPORT-FROM-CUSTOMER
    set protocols bgp group CUSTOMER-PEERS export EXPORT-TO-CUSTOMER
    set protocols bgp group CUSTOMER-PEERS neighbor 192.168.2.2 peer-as 65003
    set protocols bgp group CUSTOMER-PEERS neighbor 192.168.2.2 description "Customer - AS65003"

    Full Configuration Example

    Here's the complete configuration in JunOS hierarchical format, ready to load in a

    configure
    session. This represents a realistic dual-peer setup for a network running AS 65001, with one upstream provider peer and one customer peer.

    policy-options {
        prefix-list CUSTOMER-PREFIXES {
            172.16.10.0/24;
            172.16.20.0/24;
            172.16.30.0/24;
        }
        prefix-list INTERNAL-LOOPBACKS {
            10.0.0.0/24;
        }
        prefix-list DEFAULT-ROUTE {
            0.0.0.0/0;
        }
        as-path PEER-ORIGINATED "^65002$";
        as-path CUSTOMER-AS "^65003$";
        as-path ANY-AS ".*";
        community UPSTREAM-PEER members 65001:100;
        community CUSTOMER-ROUTE members 65001:200;
        community LOCAL-PREF-HIGH members 65001:300;
        community NO-EXPORT members no-export;
        policy-statement IMPORT-FROM-UPSTREAM {
            term ACCEPT-DEFAULT {
                from {
                    prefix-list DEFAULT-ROUTE;
                }
                then {
                    local-preference 150;
                    community add UPSTREAM-PEER;
                    accept;
                }
            }
            term REJECT-RFC1918-10 {
                from {
                    prefix-list-filter 10.0.0.0/8 orlonger;
                }
                then reject;
            }
            term REJECT-RFC1918-172 {
                from {
                    prefix-list-filter 172.16.0.0/12 orlonger;
                }
                then reject;
            }
            term REJECT-RFC1918-192 {
                from {
                    prefix-list-filter 192.168.0.0/16 orlonger;
                }
                then reject;
            }
            term ACCEPT-REMAINDER {
                then accept;
            }
        }
        policy-statement EXPORT-TO-UPSTREAM {
            term ADVERTISE-CUSTOMER {
                from {
                    prefix-list CUSTOMER-PREFIXES;
                }
                then {
                    community set CUSTOMER-ROUTE;
                    accept;
                }
            }
            term ADVERTISE-LOOPBACKS {
                from {
                    prefix-list INTERNAL-LOOPBACKS;
                }
                then accept;
            }
            term REJECT-EVERYTHING {
                then reject;
            }
        }
        policy-statement IMPORT-FROM-CUSTOMER {
            term ACCEPT-CUSTOMER-PREFIXES {
                from {
                    prefix-list CUSTOMER-PREFIXES;
                    as-path CUSTOMER-AS;
                }
                then {
                    local-preference 100;
                    community add CUSTOMER-ROUTE;
                    accept;
                }
            }
            term REJECT-ALL {
                then reject;
            }
        }
        policy-statement EXPORT-TO-CUSTOMER {
            term SEND-DEFAULT {
                from {
                    prefix-list DEFAULT-ROUTE;
                    protocol static;
                }
                then accept;
            }
            term REJECT-EVERYTHING {
                then reject;
            }
        }
    }
    protocols {
        bgp {
            local-as 65001;
            group UPSTREAM-PROVIDERS {
                type external;
                import IMPORT-FROM-UPSTREAM;
                export EXPORT-TO-UPSTREAM;
                neighbor 192.168.1.2 {
                    peer-as 65002;
                    description "Upstream Provider - AS65002";
                }
            }
            group CUSTOMER-PEERS {
                type external;
                import IMPORT-FROM-CUSTOMER;
                export EXPORT-TO-CUSTOMER;
                neighbor 192.168.2.2 {
                    peer-as 65003;
                    description "Customer - AS65003";
                }
            }
        }
    }

    Verification Steps

    After committing, the first thing I do is confirm the sessions are still up. A badly formed policy won't usually reset the session, but it's worth checking immediately after commit.

    show bgp summary

    You're looking for

    Establ
    in the State column for each peer. If you see
    Active
    or
    Idle
    , that's a session-level problem unrelated to policy — check your neighbor address, peer-AS, and whether TCP 179 is reachable.

    To verify what routes you're receiving from a specific peer and whether your import policy applied the expected attributes:

    show route receive-protocol bgp 192.168.1.2
    show route receive-protocol bgp 192.168.1.2 detail

    The

    detail
    output shows communities, local preference, and other attributes that your import policy should have set. Confirm that the communities you expected to add are present and that local-preference values match what you configured. If the default route is arriving with local-preference 150 and the UPSTREAM-PEER community stamped on it, your import policy is working correctly.

    For export policy verification, check exactly what you're advertising to a peer after policy is applied:

    show route advertising-protocol bgp 192.168.1.2

    This shows the routes your router is actually sending after applying the export policy. Cross-reference this with your intent — if you expect three prefixes and you see more or fewer, something in your export policy isn't matching what you think it is.

    One of the most useful debugging tools in JunOS is the policy simulator. You can test a policy against the routing table without committing anything or touching a live session:

    test policy EXPORT-TO-UPSTREAM 172.16.10.0/24
    test policy IMPORT-FROM-UPSTREAM 0.0.0.0/0

    The output tells you whether the route matched, which term matched it, and what actions were applied. I use this constantly when writing new policies or debugging why a prefix isn't being advertised. It's one of JunOS's genuinely superior troubleshooting features compared to other platforms.

    To verify prefix lists resolved correctly after you defined them:

    show policy prefix-list CUSTOMER-PREFIXES

    And to verify an AS-path regex is actually matching what you think it will before you rely on it in policy:

    show route aspath-regex "^65002$"

    This shows all routes currently in the routing table that match that expression — a quick sanity check that your regex is syntactically valid and semantically correct.

    Common Mistakes

    The implicit reject catches more engineers than anything else. You write a beautiful import policy that tags routes with communities and sets local preference, commit it, and then wonder why routes aren't being installed. You forgot a

    then accept
    . Every term that doesn't explicitly accept or reject falls through to the next term, and if nothing matches, the route gets rejected. Always end your policies with a deliberate catch-all, and make sure it's intentional — either accept everything that made it this far, or reject it explicitly.

    Confusing

    community add
    ,
    community set
    , and
    community delete
    causes subtle bugs that can take a while to track down.
    set
    replaces all communities on the route with the ones you specify.
    add
    appends to whatever communities are already present. Use
    set
    when you want a clean stamp; use
    add
    when the route may already carry communities you need to preserve. I've seen operators use
    set
    in an import policy and inadvertently strip communities sent by the peer that were carrying important traffic engineering signals.

    Multiple policies applied to the same neighbor form an ordered chain, evaluated left to right. The first policy that accepts or rejects a route wins — subsequent policies in the chain aren't consulted for that route. So if you have

    import [POLICY-A POLICY-B]
    and POLICY-A accepts everything, POLICY-B is never evaluated for anything. Order matters, and a catch-all accept in an early policy silently swallows all traffic engineering logic in every policy that follows it.

    Another common issue: modifying a policy and committing it does not automatically re-evaluate routes that have already been received. Your router won't reprocess existing BGP routes with the new policy unless something triggers a route refresh. To manually trigger this without resetting the session:

    clear bgp neighbor 192.168.1.2 soft in

    The

    soft in
    flag sends a ROUTE-REFRESH request to the peer, causing it to re-advertise its routes which then get processed through your updated import policy. If you need to trigger re-evaluation of export policy, use
    soft out
    instead. Avoid a hard session reset in production — it drops the session completely, triggers BGP convergence on the other end, and causes unnecessary traffic disruption.

    Finally, don't overlook the interaction between policy and routing instances. If you're running VRFs, a policy applied inside a routing instance operates in that instance's context. A prefix list defined at the global level is accessible from any routing instance, but a policy referencing

    protocol bgp
    in its from conditions matches BGP routes within the instance where the policy is applied. Test in the exact context where the policy will run, not just from the default routing instance.


    BGP route policy on Juniper is one of those areas where the fundamentals are straightforward but production environments quickly reveal edge cases. Get comfortable with

    test policy
    before you commit anything to a live session — it's the single best habit you can build. Once you have a working policy framework in place, extending it for new peers, traffic engineering requirements, or community-based routing decisions becomes a matter of adding terms rather than rethinking the whole structure.

    Frequently Asked Questions

    What is the difference between import and export policy in Juniper BGP?

    An import policy in JunOS is applied to routes received from a BGP peer — it controls which routes are accepted into the local routing table and how they're treated (local preference, community tags, etc.). An export policy is applied to routes being advertised out to a peer — it controls which routes from your routing table are sent and how they're modified before being advertised. Both types have an implicit reject-all default for eBGP sessions, so every policy needs explicit accept terms for routes you want to process.

    Why aren't my BGP routes being advertised after I apply an export policy in JunOS?

    The most common cause is a missing catch-all accept term at the end of your export policy. In JunOS, the implicit default for eBGP export is to reject everything not explicitly accepted. If your policy has terms that match and tag routes but no final 'then accept' action, those routes get rejected before they're advertised. Add a term at the bottom of your policy with no 'from' conditions and 'then accept' for routes you want to pass through, or 'then reject' to make the reject explicit and intentional.

    How do I test a Juniper route policy without affecting live BGP sessions?

    Use the 'test policy' operational command: 'test policy POLICY-NAME prefix/length'. This simulates running a specific route through the named policy and shows you which term matched, what actions were applied, and whether the route was accepted or rejected — all without committing any changes or touching a live BGP session. It's the safest way to validate policy logic before deploying it.

    Do I need to reset my BGP session after changing a route policy in JunOS?

    No — you don't need to reset the session, and you shouldn't in production. After committing a policy change, use 'clear bgp neighbor X.X.X.X soft in' to send a ROUTE-REFRESH request and have the peer re-advertise its routes through your updated import policy. For export policy changes, use 'soft out'. The soft variants trigger re-evaluation without dropping the session, avoiding unnecessary BGP convergence events on the peer side.

    What is the difference between 'community add' and 'community set' in a Juniper route policy?

    'community set' replaces all BGP communities on a route with the community or communities you specify, discarding any that were already present. 'community add' appends your specified community to whatever communities the route already carries. Use 'set' when you want a clean, controlled community stamp with no inherited values; use 'add' when you need to preserve communities already on the route — for example, communities signaled by a peer for traffic engineering purposes.

    Related Articles