PPPoE + IPv6 on JunOS
I spent far too long trying to get a Juniper BNG to delegate IPv6 addresses to PPPoE clients, so I'm putting my final config here for posterity in the hope that it helps someone else.
I'm assuming that anyone reading this already has the prerequisites in place:
- IPv6 allocation from an RIR, which you are announcing to your BGP peers.
- OSPFv3 configured and distributing IPv6 routes.
- RADIUS etc. is configured and working.
- PPPoE configured, with clients connecting, getting an IPv4 address, and able to browse the internet.
With that out of the way, let's start with the access knob. We need to add two IPv6 address pools. One of these will be for the link-net between the PPPoE client and the PPPoE server (your Juniper BNG).
access {
address-assignment {
neighbor-discovery-router-advertisement POOL-v6;
pool DHCP-POOL-v6 {
family inet6 {
prefix 2026:1234:3::/48;
range subs prefix-length 56;
}
}
pool POOL-v6 {
family inet6 {
prefix 2026:1234:0:5::/64;
range ndra prefix-length 128;
}
}
}
}Note that I'm leaving out the v4-related pools but they are very much still there.
DHCP-POOL-v6 is the pool from which IPv6 delegations will be assigned to each client - a /56 for each client, assigned from the /48 that we've defined as our prefix.
POOL-v6 is the neighbour discovery pool - a /128 will be assigned from this /64 to the WAN interface of the PPPoE client using router advertisement. subs and ndra are arbitrary names that I chose to make it clearer what each pool does.
The NDRA pool doesn't require any additional configuration at this point but the delegation pool does. From the name you can tell that we're going to use DHCPv6 as our allocation protocol which means we need to enable that service on the router:
system {
services {
dhcp-local-server {
dhcpv6 {
overrides {
delegated-pool DHCP-POOL-v6;
}
group DHCP6 {
interface pp0.0;
}
}
}
}The gist of this configuration is that we want to delegate addresses from DHCP-POOL-v6 via interfaces in the DHCP6 pool (pp0.0 in this case, which is the virtual interface that's used as the basis for PPPoE sessions in JunOS).
Which brings us to...
dynamic-profiles {
pppoe-v6-profile {
interfaces {
pp0 {
unit "$junos-interface-unit" {
actual-transit-statistics;
ppp-options {
chap;
initiate-ncp dual-stack-passive;
}
pppoe-options {
underlying-interface "$junos-underlying-interface";
server;
}
keepalives interval 30;
family inet {
filter {
input "$junos-input-filter";
output "$junos-output-filter";
}
unnumbered-address lo0.0;
}
family inet6 {
address $junos-ipv6-address;
}
}
}
}
protocols {
router-advertisement {
interface "$junos-interface-name" {
link-mtu;
prefix $junos-ipv6-ndra-prefix {
valid-lifetime 14400;
preferred-lifetime 14400;
}
}
}
}
}
}There's a lot in this, but at a high-level what I've done is created a dynamic profile called pppoe-v6-profile for dual-stack connections. Taking it in sections:
interfaceis where we definepp0.0for dual-stack connections.actual-transit-statisticsmakes sure that our interim accounting updates contain actual time/volume stats- in
ppp-optionswe're usingchapfor authentication and have instructed the BNG to negotiateipandipv6passively (dual-stack-passive). This means that the BNG will allow the client to decide which network control protocol(s) to use - IPCP or IPv6CP - instead of actively requesting that the client negotiate both, allowing the connection to come up even if the client only support IPCP. pppoe-optionstells the BNG that we want it to operate a server on the underlying interface (i.e. whichever physical interface the PPPoE connection is coming in on).- The
family inetandfamily inet6stanzas are pretty straightforward; they essentially anchor the virtualpp0.xinterface that's created for the client to a real IP address on the BNG, usually the loopback addresses.
- Under
protocolswe haverouter-advertisement- this takes the NDRA pool that we defined earlier (underaccess address-assignment) and advertises it across the PPP link to the client.
Looks complicated but it's not really. The dual-stack-passive line under ppp-options means that we could actually use this dynamic profile as our default dynamic profile without causing issues for devices that are only configured for IPv4. I'm going to assign this profile through RADIUS instead.
From a JunOS point of view we're pretty much done - the only thing that really remains to be done is to add an export policy to OSPF3 so that the DHCPv6 pool is advertised around your network (including to your edge routers). Something along the lines of:
policy-options {
policy-statement export-ospf3-pppoe-delegations {
term 10 {
from {
family inet6;
route-filter 2026:1234:3::/48 longer;
}
then accept;
}
}
}We use longer here because each client will be assigned a /56 from the /48 that we defined in our pool.
The last thing that needs to be done is to add the following attributes and values to the client's RADIUS profile (either directly through radreply or as part of a group of attributes:
| Attribute | op | Value |
|---|---|---|
| Framed-IPv6-Pool | := | POOL-v6 |
| ERX-Client-Profile-Name | := | pppoe-v6-profile |
| ERX-IPv6-Delegated-Pool-Name | := | DHCP-POOL-v6 |
Again, this is in addition to whatever attributes you already have defined for the basic IPv4 service.
And that's pretty much it! Assuming I haven't forgotten anything you should now be able to enable IPv6 on your client device, bring up a new PPPoE session, and have IPv6 working!