BGP – remove-private
1. Intro
When advertising AS paths to remote systems, have the local system strip private AS numbers from the AS path. The numbers are stripped from the AS path starting at the left end of the AS path (the end where AS paths have been most recently added). The routing device stops searching for private ASs when it finds the first nonprivate AS or a peer’s private AS. If the AS path contains the AS number of the external BGP (EBGP) neighbor, BGP does not remove the private AS number.
We will put this to the test using the following setup:

In our setup, R2 is receiving the 192.168.50.0/26 prefix from R3, but this prefix was originated many hops away. Before R2 will advertise the 192.168.50.0/26 to R1, it will strip away the private AS numbers.
The configuration template is basic. The BGP group TO-R1 will be configured with different remove-private options. We will configure different AS numbers to explore different scenarios, but the template is the following:
root@R2# show protocols bgp | display set
set protocols bgp group TO-R1 remove-private
set protocols bgp group TO-R1 peer-as xxxxx
set protocols bgp group TO-R1 neighbor 17.8.0.1
set protocols bgp group TO-R3 peer-as yyyyy
set protocols bgp group TO-R3 neighbor 17.8.8.2
2. remove-private
Initially, the remove-private knob is not configured.
### R2 view:
root@R2# run show route protocol bgp
inet.0: 23 destinations, 23 routes (23 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:12:47, localpref 100
AS path: 65310 65320 65300 400 65500 65500 65500 I, validation-state: unverified
> to 17.8.8.2 via ge-0/0/2.0
### R1 view:
root@R1# run show route protocol bgp
inet.0: 25 destinations, 25 routes (25 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:02:59, localpref 100
AS path: 200 65310 65320 65300 400 65500 65500 65500 I, validation-state: unverified
> to 17.8.0.2 via ge-0/0/1.0
### Add 'remove-private':
root@R2# show | compare
[edit protocols bgp group AS65535]
+ remove-private;
[edit]
root@R2# commit
commit complete
### Impact on R1:
root@R1# run show route protocol bgp
inet.0: 25 destinations, 25 routes (25 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:00:01, localpref 100
AS path: 200 400 65500 65500 65500 I, validation-state: unverified
> to 17.8.0.2 via ge-0/0/1.0
If we read again the definition, we see the following:
- the numbers are stripped from the AS path starting at the left end (AS path: 65310 65320 65300 400 65500 65500 65500 I)
- the routing device stops searching for private ASs when it finds the first nonprivate AS (in our case, this is AS 400)
3. remove-private all
But what if we want to remove all private AS numbers? then we just add the ‘remove-private all‘ knob.
### R2 view:
root@R2# run show route protocol bgp
inet.0: 23 destinations, 23 routes (23 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:00:16, localpref 100
AS path: 65310 65320 65300 400 65500 65500 65500 I, validation-state: unverified
> to 17.8.8.2 via ge-0/0/2.0
### Add the 'remove-private all' knob:
root@R2# show | compare
[edit protocols bgp group AS65535 remove-private]
+ all;
[edit]
root@R2# commit
commit complete
### Impact on R1:
root@R1# run show route protocol bgp
inet.0: 25 destinations, 25 routes (25 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:00:08, localpref 100
AS path: 200 400 I, validation-state: unverified
> to 17.8.0.2 via ge-0/0/1.0
4. remove-private all replace
When the all knob is configured, instead of removing, we can also replace the AS numbers:
### R2 view:
root@R2# run show route protocol bgp
inet.0: 23 destinations, 23 routes (23 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:00:16, localpref 100
AS path: 65310 65320 65300 400 65500 65500 65500 I, validation-state: unverified
> to 17.8.8.2 via ge-0/0/2.0
### Configure replace:
root@R2# show | compare
[edit protocols bgp group AS65535 remove-private all]
+ replace;
[edit]
root@R2# commit
commit complete
### Impact on R1. All private AS numbers were replaed with own AS:
root@R1# run show route protocol bgp
inet.0: 25 destinations, 25 routes (25 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:02:41, localpref 100
AS path: 200 200 200 200 400 200 200 200 I, validation-state: unverified
> to 17.8.0.2 via ge-0/0/1.0
But this is not ideal, we have an as-path loop for AS 200. We will fix this next.
5. remove-private all replace nearest
To remove the as-path loop we created in the previous section for AS 200 we can use the nearest knob:
### R2 view:
root@R2# run show route protocol bgp
inet.0: 23 destinations, 23 routes (23 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:00:16, localpref 100
AS path: 65310 65320 65300 400 65500 65500 65500 I, validation-state: unverified
> to 17.8.8.2 via ge-0/0/2.0
### Add the 'nearest' option:
root@R2# set protocols bgp group AS65535 remove-private all replace nearest
root@R2# show | compare
[edit protocols bgp group AS65535 remove-private all replace]
+ nearest;
[edit]
root@R2# commit
commit complete
### Impact on R1:
root@R1# run show route protocol bgp
inet.0: 25 destinations, 25 routes (25 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:02:01, localpref 100
AS path: 200 200 200 200 400 400 400 400 I, validation-state: unverified
> to 17.8.0.2 via ge-0/0/1.0
We can see that 65500 65500 65500 AS numbers were replaced with the nearest AS number: 400 400 400. This looks better now.
6. First AS is nonprivate
The routing device stops searching for private ASs when it finds the first nonprivate AS, but what if the 1st AS in the path is a non private one?
### Rollback the config, ('all' knob is removed):
root@R2# show protocols bgp | display set
set protocols bgp group AS65535 remove-private
set protocols bgp group AS65535 peer-as 65100
set protocols bgp group AS65535 neighbor 17.8.0.1
set protocols bgp group AS65002 peer-as 65300
set protocols bgp group AS65002 neighbor 17.8.8.2
### R2 view:
root@R2# run show route protocol bgp
inet.0: 23 destinations, 23 routes (23 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:00:08, localpref 100
AS path: 310 65320 65300 400 65500 65500 65500 I, validation-state: unverified
> to 17.8.8.2 via ge-0/0/2.0
### No impact on R1:
root@R1# run show route protocol bgp
inet.0: 25 destinations, 25 routes (25 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:00:02, localpref 100
AS path: 200 310 65320 65300 400 65500 65500 65500 I, validation-state: unverified
> to 17.8.0.2 via ge-0/0/1.0
As the definition is saying, stop at the 1st non private AS number. So, if the 1st AS is a non private one, then no action is taken.
To remove the ‘stop at the 1st non private AS number’ rule, we can add the all knob.
root@R2# set protocols bgp group AS65535 remove-private all
[edit]
root@R2# commit
commit complete
root@R1# run show route protocol bgp
inet.0: 25 destinations, 25 routes (25 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:00:02, localpref 100
AS path: 200 310 400 I, validation-state: unverified
> to 17.8.0.2 via ge-0/0/1.0
### If desired, we can continue with 'replace' / 'replace nearest':
root@R2# set protocols bgp group AS65535 remove-private all replace nearest
[edit]
root@R2# commit
commit complete
root@R1# run show route protocol bgp
inet.0: 25 destinations, 25 routes (25 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:00:03, localpref 100
AS path: 200 310 310 310 400 400 400 400 I, validation-state: unverified
> to 17.8.0.2 via ge-0/0/1.0
7. no-peer-loop-check
This will apply in a very specific use case, let’s see the official documentation:
By default, the remove-private statement has a peer loop check restriction. If a private AS in the AS path has the same value as the configured peer-as for the neighbor, remove-private does not remove or replace this private AS number. This restriction provides peer-as loop protection. However, you can remove this restriction using the no-peer-loop-check option.
To test this ourselves, let’s reset the setup so that R1 and R3 have the same 65100 AS:
### R2 view:
root@R2# run show route protocol bgp
inet.0: 23 destinations, 23 routes (23 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
192.168.50.0/26 *[BGP/170] 00:00:15, localpref 100
AS path: 65100 65300 400 65500 65500 65500 I, validation-state: unverified
> to 17.8.8.2 via ge-0/0/2.0
### Well, in this case we have an as-path loop:
root@R1# run show route protocol bgp extensive hidden
inet.0: 25 destinations, 25 routes (24 active, 0 holddown, 1 hidden)
192.168.50.0/26 (1 entry, 0 announced)
BGP /-101
Next hop type: Router, Next hop index: 598
Address: 0x7bbe424
Next-hop reference count: 1, key opaque handle: 0x0, non-key opaque handle: 0x0
Kernel Table Id: 0
Source: 17.8.0.2
Next hop: 17.8.0.2 via ge-0/0/1.0, selected
Session Id: 356
State: <Hidden Ext>
Local AS: 65100 Peer AS: 200
Age: 27
Validation State: unverified
Task: BGP_200.17.8.0.2
AS path: 200 65100 65300 400 65500 65500 65500 I (Looped: 65100)
Localpref: 100
Router ID: 17.0.0.2
Hidden reason: AS path loop
Thread: junos-main
### Note: If you wonder, we can see the prefix on R1 because R2 was configured with advertise-peer-as and R1 with BGP 'keep all':
While this can be a safety mechanism for as-path loop prevention, we can override this by applying the ‘no-peer-loop-check‘ knob, to force R2 to remove the private AS.
### Add the 'no-peer-loop-check'.
### Also, remove the 'advertise-peer-as', just to be sure it has no influence.
root@R2# show | compare
[edit protocols bgp group AS65535]
- advertise-peer-as;
[edit protocols bgp group AS65535 remove-private]
+ no-peer-loop-check;
[edit]
root@R2# commit
commit complete
### Now the prefix advertised to R1.
### All private AS numbers were removed until 1st non private AS number found:
root@R1# run show route protocol bgp extensive
inet.0: 25 destinations, 25 routes (25 active, 0 holddown, 0 hidden)
192.168.50.0/26 (1 entry, 1 announced)
TSI:
KRT in-kernel 192.168.50.0/26 -> {17.8.0.2}
*BGP Preference: 170/-101
Next hop type: Router, Next hop index: 598
Address: 0x7bbe424
Next-hop reference count: 2, key opaque handle: 0x0, non-key opaque handle: 0x0
Kernel Table Id: 0
Source: 17.8.0.2
Next hop: 17.8.0.2 via ge-0/0/1.0, selected
Session Id: 356
State: <Active Ext>
Local AS: 65100 Peer AS: 200
Age: 1:11
Validation State: unverified
Task: BGP_200.17.8.0.2
Announcement bits (1): 0-KRT
AS path: 200 400 65500 65500 65500 I
Accepted
Localpref: 100
Router ID: 17.0.0.2
Thread: junos-main
External Resources: