I've also made a quick patch for the kerenel protocol to accept routes of
type local. But it might be not well backward-compatible, because somebody
might receive some new routes in their kernel protocols. Anyway, with this
patch you can use something like that to have your IP route:

protocol kernel6 {
    kernel table 255; # table local
    learn all; # accept kernel routes as well
    scan time 10;
    ipv6 {
        import all;
        export none;
    };
}

On Tue, Sep 30, 2025 at 8:39 PM Alexander Zubkov <[email protected]> wrote:

> Hi Anthony,
>
> You mean you have for example ip address with mask configured on eth0:
> 2001:db8::cafe/64. And you want to have route 2001:db8::cafe/128 inside
> bird without having to specify it manually in a static protocol for
> example? And now you have to make a dummy interface with 2001:db8::cafe/128
> configured on it?
> AFAIK, you cannot do that automatically in bird (i.e. change network mask
> of prefix). I thought if it would be possible to import single IP route
> from "table local", Linux has such routes for IPs configured for the system:
>
> local 2001:db8::cafe dev eth0 table local proto kernel metric 0 pref medium
>
> But bird ignores routes with type local, so it would need some patching of
> the source to do that.
> Also IMHO, having IPs with overlapping prefixes should work well on Linux
> if you know what you do.
> You can also use such config, when you configure for
> example 2001:db8::cafe/128 on eth0 and add device-route for 2001:db8::/64
> on dev eth0. But that might not work for automatic configurations - DHCP,
> SLAAC.
>
> Regards,
> Alexander Zubkov
>
>
> On Tue, Sep 30, 2025 at 7:24 PM Anthony Hoppe via Bird-users <
> [email protected]> wrote:
>
>> Hello List!
>>
>> I am working on a project to bring L3 down to the individual host and
>> am thinking through the transitionary configuration.
>>
>> For the purposes of this discussion, the hosts are assigned IPv4
>> addresses within a /24 and IPv6 addresses within a /64.
>>
>> Currently, I'm using a dummy interface and adding the IPs they own as
>> v4 /32 and v6 /128 and in combination with an export filter to only
>> export /32 and /128 prefixes, this works great.
>>
>> However, I was wondering if there is a way to configure BIRD so that
>> for the IPs configured on the host it supplants the configured prefix
>> with /32 and/or /128 allowing me to eliminate the dummy interface?
>>
>> The dummy interface is mostly a transitory step as Linux (Debian, at
>> least) will not let me assign a /32 or /128 to an interface where a
>> larger overlapping prefix resides (which yes, I understand why you
>> normally don't want to do this, haha).
>>
>> ~ Anthony
>>
>> --
>> This email, including its contents and any attachment(s), may contain
>> confidential and/or proprietary information and is solely for the review
>> and use of the intended recipient(s). If you have received this email in
>> error, please notify the sender and permanently delete this email, its
>> content, and any attachment(s).  Any disclosure, copying, or taking of
>> any
>> action in reliance on an email received in error is strictly prohibited.
>>
>
diff --git a/nest/config.Y b/nest/config.Y
index 4a3b45b50..acc1a09cf 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -137,7 +137,7 @@ CF_ENUM(T_ENUM_RTS, RTS_, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
 	RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL, RPKI, L3VPN,
 	AGGREGATED)
 CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED)
-CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT)
+CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT, LOCAL)
 CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
 CF_ENUM(T_ENUM_ASPA, ASPA_, UNKNOWN, VALID, INVALID)
 CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
diff --git a/nest/route.h b/nest/route.h
index 5a9e7fa16..24fb73193 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -491,7 +491,8 @@ typedef struct rta {
 #define RTD_BLACKHOLE 2			/* Silently drop packets */
 #define RTD_UNREACHABLE 3		/* Reject as unreachable */
 #define RTD_PROHIBIT 4			/* Administratively prohibited */
-#define RTD_MAX 5
+#define RTD_LOCAL 5			/* Accept locally */
+#define RTD_MAX 6
 
 #define IGP_METRIC_UNKNOWN 0x80000000	/* Default igp_metric used when no other
 					   protocol-specific metric is availabe */
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index e10e1ecbf..33b3aff83 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -86,6 +86,7 @@ const char * rta_dest_names[RTD_MAX] = {
   [RTD_BLACKHOLE]	= "blackhole",
   [RTD_UNREACHABLE]	= "unreachable",
   [RTD_PROHIBIT]	= "prohibited",
+  [RTD_LOCAL]		= "local",
 };
 
 pool *rta_pool;
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index 299f132fe..a01c45c57 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -1770,6 +1770,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
     case RTN_PROHIBIT:
       ra->dest = RTD_PROHIBIT;
       break;
+    case RTN_LOCAL:
+      ra->dest = RTD_LOCAL;
+      break;
     /* FIXME: What about RTN_THROW? */
     default:
       SKIP("type %d\n", i->rtm_type);

Reply via email to