Unexpected WAN DHCPv6-PD restart triggered by LAN link state changes

Started by PoMpIs, Today at 09:38:18 PM

Previous topic - Next topic
I am seeing an issue where a physical link change on a LAN interface causes IPv6 on the PPPoE WAN to be reconfigured/restarted.

Setup
OPNsense 26.7.2_2
WAN: PPPoE on pppoe0
ISP: DIGI Spain
DHCPv6-PD: /56
LAN interfaces: Intel E810 (ice0, ice1, ice2)
WAN interface: Intel X550-T2

The problem is easy to reproduce: if a device is connected directly to a LAN interface and that device is powered off or the cable is disconnected, the LAN interface goes LINK_DOWN.

Shortly afterwards, OPNsense triggers IPv6 processing on pppoe0 and DHCPv6-PD is restarted/reconfigured, causing loss of IPv6 connectivity on all LAN/VLAN interfaces using the delegated prefix.

The PPPoE WAN itself does not go down and IPv4 remains working.

This is not specific to the Intel E810. I have reproduced the same behaviour with several different NICs.

I also reproduced the issue after replacing Kea/radvd on the affected LAN with dnsmasq handling DHCPv6 and Router Advertisements, so the problem does not appear to be specific to Kea or radvd.

Behaviour after the LAN link event

When the issue is triggered, dhcp6c on pppoe0 gets stuck in the SOLICIT state and keeps retransmitting without receiving an ADVERTISE:

Sending Solicit on pppoe0
send so
licit to ff02::1:2%pppoe0
reset a timer on pppoe0, state=SOLICIT, timeo=6, retrans=72361

Sending Solicit on pppoe0
send solicit to ff02::1:2%pppoe0
reset a timer on pppoe0, state=SOLICIT, timeo=7, retrans=144580

Shortly afterwards, the LAN interfaces lose their delegated IPv6 prefixes and radvd reports errors such as:

radvd_configure_do(manual) found no suitable IPv6 address on opt11(ice0)
radvd_configure_do(manual) found no suitable IPv6 address on opt3(vlan011)
radvd_configure_do(manual) found no suitable IPv6 address on opt6(vlan050)

A normal DHCPv6-PD negotiation after boot completes almost immediately:

SOLICIT -> ADVERTISE -> REQUEST -> REPLY

So the failure only appears after DHCPv6-PD processing is triggered by the LAN link-state event.

Workaround

As a workaround, I modified /usr/local/etc/rc.linkup to ignore link events from the affected LAN interfaces.

With those LAN link events ignored, powering devices on/off or disconnecting the cable no longer affects the WAN IPv6 connection.

The added workaround is:

#!/usr/local/bin/php
<?php

/*
* Copyright (C) 2003-2005 Scott Ullrich <sullrich@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
*/

require_once("config.inc");
require_once(
"auth.inc");
require_once(
"filter.inc");
require_once(
"interfaces.inc");
require_once(
"util.inc");
require_once(
"system.inc");

exit_on_bootup();

if (
$argc < 3) {
   exit;
}

// Workaround for an issue where a physical LINK_UP/LINK_DOWN event on a LAN
// interface causes OPNsense to trigger IPv6 WAN processing on pppoe0.
//
// In my setup, powering off a device directly connected to ice0/ice1/ice2
// can indirectly trigger DHCPv6-PD reconfiguration on the unrelated PPPoE WAN,
// resulting in loss of IPv6 connectivity.
//
// Ignoring DEVD link events from these LAN interfaces completely prevents
// the unwanted DHCPv6-PD reset/reconfiguration.
//
// This is only a workaround for debugging/reporting purposes.
$ignored_interfaces = [
   
'ice0',
   
'ice1',
   
'ice2',
];

$action = $argv[1];
$device = $argv[2];

// Stop processing LAN carrier events before they can propagate further
// through rc.linkup and eventually affect WAN IPv6/DHCPv6-PD handling.
if (in_array($device, $ignored_interfaces, true)) {
   
log_msg(sprintf(
       
"DEVD: Ignored Ethernet %s event for %s to avoid DHCPv6-PD reset",
       
$action,
       
$device
   
));
   exit;
}

function
handle_argument_group($action, $device)
{
   global
$config;

   
$interface = convert_real_interface_to_friendly_interface_name($device);

   if (empty(
$interface)) {
       return;
   }

   if (empty(
$config['interfaces'][$interface])) {
       return;
   }

   if (!isset(
$config['interfaces'][$interface]['enable'])) {
       return;
   }

   switch (
$action) {
       case
'stop':
           
log_msg(sprintf("DEVD: Ethernet detached event for %s(%s)", $interface, $device));
           
interface_suspend($interface);
           break;

       case
'start':
           
log_msg(sprintf("DEVD: Ethernet attached event for %s(%s)", $interface, $device));
           
interface_configure(false, $interface, true, true);
           break;

       default:
           
log_msg(sprintf("DEVD: The action parameter passed is wrong (%s)", $action), LOG_ERR);
           break;
   }
}

handle_argument_group($action, $device);


I inserted this before handle_argument_group() in /usr/local/etc/rc.linkup.

Expected behaviour

I would expect a LINK_DOWN or LINK_UP event on an unrelated LAN interface not to restart or reconfigure DHCPv6-PD on pppoe0 while the PPPoE WAN itself remains up.

If I place a switch between OPNsense and the directly connected PC, the issue does not occur because the physical link on the OPNsense interface never goes down.

However, I use direct physical connections from OPNsense to some devices, so I would like to keep this topology without losing IPv6 every time one of those devices is powered off.

Thank you very much. 😊