[j-nsp] Doing SNAT only for destinations learned from a specific BGP peering
Martin Tonusoo
martin at tonusoo.ee
Mon Apr 20 07:04:02 EDT 2026
Hi.
You need Port Address Translation(PAT) and this is not possible on
MX204. On MX80 it's possible to use MS-MIC-16G multiservices MIC which
seems to support PAT:
https://www.juniper.net/documentation/us/en/hardware/mx-module-reference/topics/concept/mic-mx-series-ms.html
As Alex and Tom already mentioned, perhaps you could use filter-based
forwarding(FBF), routing-instances and an external router performing
the PAT functionality as a workaround. In principle, something like
this:
Research network -> government network:
1. Rewrite the BGP next-hop learned on prefixes on L3VPN peering to an
address of an Linux router:
root at mx> show configuration protocols bgp group as60
accept-remote-nexthop;
import rewrite-nh;
/* as traffic to L3VPN is SNATed, then there is no need to export routes */
export reject-all;
/* L3VPN connection */
neighbor 10.1.1.0 {
peer-as 60;
}
root at mx>
root at mx> show configuration policy-options policy-statement rewrite-nh
then {
next-hop 10.2.2.0;
accept;
}
root at mx>
2. Linux router receives packets on VLAN interface with 10.2.2.0/31
configured, performs the PAT and sends packets back to Juniper router:
# ip -4 r
default via 10.7.7.1 dev enp7s0.40 proto static
10.2.2.0/31 dev enp7s0.20 proto kernel scope link src 10.2.2.0
10.7.7.0/31 dev enp7s0.40 proto kernel scope link src 10.7.7.0
10.8.8.0/31 dev enp7s0.50 proto kernel scope link src 10.8.8.0
#
# nft list table ip nat
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname "enp7s0.40" snat to 10.1.1.1
}
}
#
3. Juniper router receives PATed packets on interface with 10.7.7.1/31
configured and this interface is in routing instance named
"from-linux-router":
root at mx> show configuration routing-instances from-linux-router
instance-type virtual-router;
routing-options {
static {
route 0.0.0.0/0 next-hop 10.1.1.0;
}
}
interface ge-0/0/1.40;
root at mx>
4. Besides the default route pointing to L3VPN neighbor 10.1.1.0, the
RIB associated with "from-linux-router" also contains selected direct
and local routes:
root at mx> show configuration routing-options
interface-routes {
rib-group inet direct-routes;
}
autonomous-system 40;
rib-groups {
direct-routes {
import-rib [ inet.0 from-linux-router.inet.0 ];
import-policy [ l3vpn-p2p-network lan-network reject-all ];
}
}
root at mx>
root at mx> show route table from-linux-router.inet.0
from-linux-router.inet.0: 7 destinations, 7 routes (7 active, 0
holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
0.0.0.0/0 *[Static/5] 01:53:01
> to 10.1.1.0 via ge-0/0/1.10
10.1.1.0/31 *[Direct/0] 01:53:01
> via ge-0/0/1.10
10.1.1.1/32 *[Local/0] 00:01:21
Local via ge-0/0/1.10
10.4.4.0/24 *[Direct/0] 01:50:37
> via ge-0/0/0.0
10.4.4.1/32 *[Local/0] 00:00:19
Local via ge-0/0/0.0
10.7.7.0/31 *[Direct/0] 01:53:01
> via ge-0/0/1.40
10.7.7.1/32 *[Local/0] 01:53:01
Local via ge-0/0/1.40
root at mx>
As seen above, packets with src IP 10.1.1.1 are sent to L3VPN neighbor
address 10.1.1.0.
Government network -> research network:
1. Return traffic from government network is placed to routing
instance named "to-linux-router" using a firewall:
root at mx> show configuration interfaces ge-0/0/1 unit 10
vlan-id 10;
family inet {
filter {
input l3vpn-to-linux-router;
}
address 10.1.1.1/31;
}
root at mx>
root at mx> show configuration firewall family inet filter l3vpn-to-linux-router
term accept-bgp {
from {
source-address {
10.1.1.0/32;
}
destination-address {
10.1.1.1/32;
}
protocol tcp;
destination-port 179;
}
then {
count accept-bgp;
accept;
}
}
term accept-established-bgp {
from {
source-address {
10.1.1.0/32;
}
destination-address {
10.1.1.1/32;
}
protocol tcp;
source-port bgp;
destination-port 49160-65535;
tcp-established;
}
then {
count accept-established-bgp;
accept;
}
}
term forward-to-linux-router {
from {
destination-address {
10.1.1.1/32;
}
}
then {
count forward-to-linux-router;
routing-instance to-linux-router;
}
}
root at mx>
2. The RIB for "to-linux-router" routing instance has a default route
pointing to another VLAN interface of the Linux router:
root at mx> show configuration routing-instances to-linux-router
instance-type virtual-router;
routing-options {
static {
route 0.0.0.0/0 next-hop 10.8.8.0;
}
}
interface ge-0/0/1.50;
root at mx>
root at mx> show route table to-linux-router.inet.0
to-linux-router.inet.0: 3 destinations, 3 routes (3 active, 0
holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
0.0.0.0/0 *[Static/5] 01:01:43
> to 10.8.8.0 via ge-0/0/1.50
10.8.8.0/31 *[Direct/0] 01:01:43
> via ge-0/0/1.50
10.8.8.1/32 *[Local/0] 01:01:43
Local via ge-0/0/1.50
root at mx>
3. The Linux router, with strict RPF disabled, receives traffic on
10.8.8.0, matches the packets against its active NAT state table to
reverse the translation, and sends packets based on default route back
to Juniper where it lands on "from-linux-router" routing instance.
4. As the direct network of the research network was leaked into
"from-linux-router.inet.0" table, then the Juniper router forwards
packets based on this direct route. For example:
root at mx> show route table from-linux-router.inet.0 10.4.4.10
from-linux-router.inet.0: 7 destinations, 7 routes (7 active, 0
holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
10.4.4.0/24 *[Direct/0] 02:01:31
> via ge-0/0/0.0
root at mx>
Martin
More information about the juniper-nsp
mailing list