Hello,
My lab is running 21.2R3-S9.21 on MX80 with MS-MIC's. My configuration is for a retailer on a wholesales ISP delivering internet services using IPOE and PPPOE. The current production config would just do native IPv4/IPv6 and if the customer has a managed CPE we would configure DS-Lite to save IPv4 space.
There are 2 parts of this configuration:
- Introduction of CGNAT/NAT444 for unmanaged CPE's.
- Introduction of PCP to allow customers to map external ports to their internal network, this for both CGNAT and DSLITE.
What works:
- CGNAT including PCP
- DS-Lite
What's not working:
This should be supported on the MX80 as of Junos 18.2R1 and MS-MICs:
https://apps.juniper.net/feature-explorer/feature/6245?fn=Port%20Control%20Protocol%20support%20for%20DS-Lite
There is some confusion around the nat-pool configuration online. I tested with and without "address-pooling paired", same for "secured-port-block-allocation". Neither of those changes create any difference in behavior.
Does anyone have experience with DS-Lite/PCP ? Does anyone have a working configuration snippet (even it it's for MS-DPCs) ? I've been looking at this for days now.
Technical info:
What I'm seeing is that the PCP map request is being answered with an error towards the CPE
Frame 4: 144 bytes on wire (1152 bits), 144 bytes captured (1152 bits)
Linux cooked capture v1
Internet Protocol Version 6, Src: 3ffe::2, Dst: IPV6-Internet-Customer
User Datagram Protocol, Src Port: 5351, Dst Port: 5351
Port Control Protocol, Map Response
Version: 2
1... .... = R: Response
.000 0001 = Opcode: Map (1)
Reserved: 0
Result Code: Cannot provide external port (11)
Lifetime: 30
Epoch Time: 71732
Reserved: 000000000000000000000000
Map Response
Mapping Nonce: ...
Protocol: 6
Reserved: 0
Internal Port: 8443
Assigned External Port: 8443
Assigned External IP Address: ::
Options
And this matches with the pcp statistics output:
Operational Statistics
Map request received : 829
Peer request received : 0
Other operational counters : 0
Option Statistics
Unprocessed requests received : 0
Third party requests received : 0
Prefer fail option received : 0
Filter option received : 0
Other options counters : 0
Option optional received : 829
Result Statistics
PCP success : 0
PCP unsupported version : 0
Not authorized : 0
Bad requests : 0
Unsupported opcode : 2
Unsupported option : 0
Bad option : 0
Network failure : 0
Out of resources : 0
Unsupported protocol : 0
User exceeded quota : 0
Cannot provide external : 829
Address mismatch : 0
Excessive number of remote peers : 0
Processing error : 0
Other result counters : 0
Relevant services configuration:
service-set retailer-cgnat {
syslog {
host SYSLOGSERVER {
services any;
log-prefix cgnat;
port 514;
class {
stateful-firewall-logs;
alg-logs;
nat-logs;
pcp-logs;
}
source-address 192.0.2.0;
}
}
nat-options {
land-attack-check ip-port;
max-sessions-per-subscriber 4000;
}
pcp-rules pcp-cgnat-rule;
nat-rules cgnat-rules;
next-hop-service {
inside-service-interface ms-0/2/0.2;
outside-service-interface ms-0/2/0.1;
}
}
service-set retailer-dslite {
syslog {
host SYSLOGSERVER {
services any;
port 514;
class {
nat-logs;
pcp-logs map;
}
source-address 192.0.2.0;
}
}
tcp-mss 1300;
softwire-options {
dslite-ipv6-prefix-length 128;
}
softwire-rules softwire-rule;
pcp-rules pcp-dslite-rule;
nat-rules dslite-rules;
next-hop-service {
inside-service-interface ms-0/2/0.4;
outside-service-interface ms-0/2/0.3;
}
}
softwire {
softwire-concentrator {
ds-lite sc-dslite {
softwire-address 3ffe::2;
mtu-v6 1460;
copy-dscp;
flow-limit 4000;
}
}
rule softwire-rule {
match-direction input;
term default {
then {
ds-lite sc-dslite;
}
}
}
}
nat {
pool retailer-pool1 {
address-range low 203.0.113.64 high 203.0.113.127;
port {
range low 1025 high 65535 random-allocation;
secured-port-block-allocation block-size 512 max-blocks-per-address 8 active-block-timeout 300;
}
mapping-timeout 180;
ei-mapping-timeout 180;
}
pool dslite-nat-pool1 {
address-range low 203.0.113.128 high 203.0.113.159;
port {
range low 1025 high 65535 random-allocation;
secured-port-block-allocation block-size 256 max-blocks-per-address 16 active-block-timeout 300;
}
mapping-timeout 180;
ei-mapping-timeout 180;
}
rule dslite-rules {
match-direction input;
term nat {
from {
destination-address {
10.0.0.0/8 except;
172.16.0.0/12 except;
192.168.0.0/16 except;
100.64.0.0/10 except;
any-ipv4;
}
}
then {
translated {
source-pool dslite-nat-pool1;
translation-type {
napt-44;
}
mapping-type endpoint-independent;
filtering-type {
endpoint-independent;
}
address-pooling paired;
}
}
}
}
rule cgnat-rules {
match-direction input;
term nat {
from {
source-address {
100.120.0.0/22;
}
destination-address {
10.0.0.0/8 except;
172.16.0.0/12 except;
192.168.0.0/16 except;
100.64.0.0/10 except;
any-ipv4;
}
}
then {
translated {
source-pool retailer-pool1;
translation-type {
napt-44;
}
mapping-type endpoint-independent;
filtering-type {
endpoint-independent;
}
}
}
}
}
}
pcp {
server pcp-dslite {
ipv6-address 3ffe::2;
softwire-concentrator sc-dslite;
mapping-lifetime-minimum 120;
max-mappings-per-client 10;
pcp-options third-party;
nat-options {
pool dslite-nat-pool1;
}
}
server pcp-cgnat {
ipv4-address 203.0.113.0;
mapping-lifetime-minimum 120;
max-mappings-per-client 10;
pcp-options third-party;
}
rule pcp-dslite-rule {
match-direction input;
term default {
then {
pcp-server pcp-dslite;
}
}
}
rule pcp-cgnat-rule {
match-direction input;
term default {
then {
pcp-server pcp-cgnat;
}
}
}
}
The interface configuration:
mtu 9216;
services-options {
deterministic-nat-configuration-log-interval {
interval 1800;
}
open-timeout 45;
close-timeout 90;
trio-flow-offload {
minimum-bytes 1024;
}
pba-interim-logging-interval 1800;
}
unit 0 {
family inet {
address 192.0.2.0/32;
}
}
unit 1 {
family inet;
service-domain outside;
}
unit 2 {
family inet;
service-domain inside;
}
unit 3 {
family inet;
service-domain outside;
}
unit 4 {
family inet6;
service-domain inside;
}
I'm using a PBR/FBF approach to make sure nothing is leaking into the global routing table and to protect our ds-lite setup:
rib inet6.0 {
static {
route 3ffe::2/128 {
discard;
preference 0;
}
}
}
...
interface-routes {
rib-group {
inet inet-to-cgnat;
inet6 inet6-to-dslite;
}
}
...
rib-groups {
inet-to-cgnat {
import-rib [ inet.0 cgnat-forwarding.inet.0 ];
}
inet6-to-dslite {
import-rib [ inet6.0 dslite-forwarding.inet6.0 ];
}
}
...
cgnat-forwarding {
instance-type forwarding;
routing-options {
static {
route 0.0.0.0/0 {
next-hop ms-0/2/0.2;
preference 0;
}
}
}
}
dslite-forwarding {
instance-type forwarding;
routing-options {
rib dslite-forwarding.inet6.0 {
static {
route 3ffe::2/128 {
next-hop ms-0/2/0.4;
preference 0;
}
}
}
}
}
...
firewall {
family inet {
...
filter retailer-in {
interface-specific;
term pcp {
from {
destination-address {
203.0.113.0/32;
}
source-port 5351;
destination-port 5351;
}
then {
port-mirror;
routing-instance cgnat-forwarding;
}
}
term invalid {
from {
destination-prefix-list {
cgnat_list;
}
}
then {
discard;
}
}
term cgnat {
from {
source-prefix-list {
cgnat_list;
}
}
then {
policer retailer-in-policer;
routing-instance cgnat-forwarding;
}
}
term default {
then {
policer retailer-in-policer;
}
}
}
filter retailer-out {
interface-specific;
term pcp {
from {
source-address {
203.0.113.0/32;
}
source-port 5351;
destination-port 5351;
}
then port-mirror;
}
term default {
then {
policer retailer-out-policer;
}
}
}
}
family inet6 {
...
filter retailer16-in {
interface-specific;
term pcp {
from {
destination-address {
3ffe::2/128;
}
source-port 5351;
destination-port 5351;
}
then {
port-mirror;
routing-instance dslite-forwarding;
}
}
term dslite {
from {
destination-prefix-list {
dslite_list;
}
}
then {
policer retailer-in-policer;
routing-instance dslite-forwarding;
}
}
term default {
then {
policer retailer-in-policer;
}
}
}
...
filter retailer16-out {
interface-specific;
term pcp {
from {
source-address {
3ffe::2/128;
}
source-port 5351;
destination-port 5351;
}
then port-mirror;
}
term default {
then {
policer retailer-out-policer;
}
}
}
}
...
}
Thanks for idea's and help :).
Thomas
-------------------------------------------