Re: Question about MPLS L3VPN

2024-01-27 Thread Marcel Menzel via Bird-users

Ondrej,

You can try attached patch.


Yes, that resolves it for me. Thank you for the very quick fix!

Re: Question about MPLS L3VPN

2024-01-27 Thread Ondrej Zajicek
On Sat, Jan 27, 2024 at 02:59:57PM +0100, Ondrej Zajicek wrote:
> On Sat, Jan 27, 2024 at 01:42:57PM +0100, Marcel Menzel via Bird-users wrote:
> > Hello List,
> > 
> > I am doing a test setup with the new MPLS L3VPN feature (for background
> > information: I am running IPsec with L2TP on top, with OSPF as IGP and iBGP
> > between loopbacks)
> > with one router receiving an IPv6 fulltable via eBGP and the other one
> > establishing the BGP session through a tunnel described above, and I noticed
> > periodic high CPU usage on the router receiving the routes at the end of the
> > tunnel.
> > 
> > It seems, that BIRD keeps exporting the whole table to the kernel every 30
> > seconds, as it is configured in the kernel protocol scan time with the "vrf"
> > directive set:
> 
> Hello
> 
> It is possible that BIRD exports some route but receives back from kernel
> something slightly different than it expected, so it will try to re-send
> it during the scan.
>
> ... and i just noticed that the bug manifests even in my test case, so
> i will check it.

Fixed:

https://gitlab.nic.cz/labs/bird/-/commit/f40e2bc270d3635be518ae80251ce0b5c519c6f4

You can try attached patch.

-- 
Elen sila lumenn' omentielvo

Ondrej 'Santiago' Zajicek (email: santi...@crfreenet.org)
"To err is human -- to blame it on a computer is even more so."
commit f40e2bc270d3635be518ae80251ce0b5c519c6f4
Author: Ondrej Zajicek 
Date:   Sat Jan 27 17:38:06 2024 +0100

Nest: Fix bug in recursive routes with MPLS-labeled nexthops

When a recursive route with MPLS-labeled nexthop was exported to kernel
and read back, the nexthop_same() failed due to different labels_orig
field and kernel protocol reinstalled it unnecessarily.

For comparing hext hops, route cache has to distinguish ones with
different labels_orig, but KRT has to ignore that, so we need two
nexthop compare functions.

Thanks to Marcel Menzel for the bugreport.

diff --git a/nest/route.h b/nest/route.h
index d26a4b8c..e6f6c64a 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -694,6 +694,9 @@ static inline size_t nexthop_size(const struct nexthop *nh)
 int nexthop__same(struct nexthop *x, struct nexthop *y); /* Compare multipath nexthops */
 static inline int nexthop_same(struct nexthop *x, struct nexthop *y)
 { return (x == y) || nexthop__same(x, y); }
+int nexthop_equal_(struct nexthop *x, struct nexthop *y); /* Compare multipath nexthops, ignore labels_orig */
+static inline int nexthop_equal(struct nexthop *x, struct nexthop *y)
+{ return (x == y) || nexthop_equal_(x, y); }
 struct nexthop *nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, linpool *lp);
 struct nexthop *nexthop_sort(struct nexthop *x);
 static inline void nexthop_link(struct rta *a, const struct nexthop *from)
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index 7f3645ee..af864bdf 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -185,20 +185,40 @@ nexthop_hash(struct nexthop *x)
   return h;
 }
 
+static inline int
+nexthop_equal_1(struct nexthop *x, struct nexthop *y)
+{
+  if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) ||
+  (x->flags != y->flags) || (x->weight != y->weight) ||
+  (x->labels != y->labels))
+return 0;
+
+  for (int i = 0; i < x->labels; i++)
+if (x->label[i] != y->label[i])
+  return 0;
+
+  return 1;
+}
+
 int
-nexthop__same(struct nexthop *x, struct nexthop *y)
+nexthop_equal_(struct nexthop *x, struct nexthop *y)
 {
+  /* Like nexthop_same(), but ignores difference between local labels and labels from hostentry */
+
   for (; x && y; x = x->next, y = y->next)
-  {
-if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) ||
-	(x->flags != y->flags) || (x->weight != y->weight) ||
-	(x->labels_orig != y->labels_orig) || (x->labels != y->labels))
+if (!nexthop_equal_1(x, y))
   return 0;
 
-for (int i = 0; i < x->labels; i++)
-  if (x->label[i] != y->label[i])
-	return 0;
-  }
+  return x == y;
+}
+
+int
+nexthop__same(struct nexthop *x, struct nexthop *y)
+{
+  for (; x && y; x = x->next, y = y->next)
+if (!nexthop_equal_1(x, y) ||
+	(x->labels_orig != y->labels_orig))
+  return 0;
 
   return x == y;
 }
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 3a4b24dc..7a078fb9 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -619,7 +619,7 @@ krt_same_dest(rte *k, rte *e)
 return 0;
 
   if (ka->dest == RTD_UNICAST)
-return nexthop_same(&(ka->nh), &(ea->nh));
+return nexthop_equal(&(ka->nh), &(ea->nh));
 
   return 1;
 }


Re: Question about MPLS L3VPN

2024-01-27 Thread Ondrej Zajicek
On Sat, Jan 27, 2024 at 01:42:57PM +0100, Marcel Menzel via Bird-users wrote:
> Hello List,
> 
> I am doing a test setup with the new MPLS L3VPN feature (for background
> information: I am running IPsec with L2TP on top, with OSPF as IGP and iBGP
> between loopbacks)
> with one router receiving an IPv6 fulltable via eBGP and the other one
> establishing the BGP session through a tunnel described above, and I noticed
> periodic high CPU usage on the router receiving the routes at the end of the
> tunnel.
> 
> It seems, that BIRD keeps exporting the whole table to the kernel every 30
> seconds, as it is configured in the kernel protocol scan time with the "vrf"
> directive set:

Hello

It is possible that BIRD exports some route but receives back from kernel
something slightly different than it expected, so it will try to re-send
it during the scan.

If you enable 'debug all' on the kernel protocol (both global and in
VRF), you can see:

2024-01-27 14:53:50.313  kernel1v6: 2001:db8:1:2::/64: seen

or:

2024-01-27 14:53:50.313  kernel2v6: 2001:db8:1:2::/64: updating

... and i just noticed that the bug manifests even in my test case, so
i will check it.

-- 
Elen sila lumenn' omentielvo

Ondrej 'Santiago' Zajicek (email: santi...@crfreenet.org)
"To err is human -- to blame it on a computer is even more so."


Question about MPLS L3VPN

2024-01-27 Thread Marcel Menzel via Bird-users

Hello List,

I am doing a test setup with the new MPLS L3VPN feature (for background 
information: I am running IPsec with L2TP on top, with OSPF as IGP and 
iBGP between loopbacks)
with one router receiving an IPv6 fulltable via eBGP and the other one 
establishing the BGP session through a tunnel described above, and I 
noticed periodic high CPU usage on the router receiving the routes at 
the end of the tunnel.


It seems, that BIRD keeps exporting the whole table to the kernel every 
30 seconds, as it is configured in the kernel protocol scan time with 
the "vrf" directive set:


root@sendak ~ # ip monitor | grep --line-buffered 2001:1568::/33 | gawk 
'{ print strftime(), $0 }'
Sat Jan 27 13:21:10 CET 2024 2001:1568::/33  encap mpls  1000 via 
fe80::9cd4:daff:feb9:cf5d dev l2tp1s0 table 1 proto bird metric 32 pref 
medium
Sat Jan 27 13:21:40 CET 2024 2001:1568::/33  encap mpls  1000 via 
fe80::9cd4:daff:feb9:cf5d dev l2tp1s0 table 1 proto bird metric 32 pref 
medium
Sat Jan 27 13:22:09 CET 2024 2001:1568::/33  encap mpls  1000 via 
fe80::9cd4:daff:feb9:cf5d dev l2tp1s0 table 1 proto bird metric 32 pref 
medium
Sat Jan 27 13:22:37 CET 2024 2001:1568::/33  encap mpls  1000 via 
fe80::9cd4:daff:feb9:cf5d dev l2tp1s0 table 1 proto bird metric 32 pref 
medium
Sat Jan 27 13:23:04 CET 2024 2001:1568::/33  encap mpls  1000 via 
fe80::9cd4:daff:feb9:cf5d dev l2tp1s0 table 1 proto bird metric 32 pref 
medium
Sat Jan 27 13:23:30 CET 2024 2001:1568::/33  encap mpls  1000 via 
fe80::9cd4:daff:feb9:cf5d dev l2tp1s0 table 1 proto bird metric 32 pref 
medium
Sat Jan 27 13:23:57 CET 2024 2001:1568::/33  encap mpls  1000 via 
fe80::9cd4:daff:feb9:cf5d dev l2tp1s0 table 1 proto bird metric 32 pref 
medium


although there's no update for that route (I'm taking here the prefix to 
monitor where the bird webserver lies in) received from upstream:

root@lotor ~ # ip monitor | grep --line-buffered 2001:1568::/33


I set different timers on the kernel protocols because trying to debug 
these was just too much noise in my logs.


As I don't think that this is desired behavior, has anyone else noticed 
this?
It might also be that systemd-networkd or strongswan keeps interfering 
here (at least systemd-networkd shows high CPU usage when the kernel RIB 
changes, strongswan did this aswell but I tweaked config for it to 
ignore BIRD routes),
but I don't see the reason why. "ManageForeignRoutingPolicyRules=no" and 
"ManageForeignRoutes=no" is set in networkd.conf and the ip monitor 
above only shows inserts.
The setup without MPLS but with separate XFRM tunnels per VRF (that's 
why I want to use L3VPN, to just have 1 Tunnel with MPLS on top) works 
flawlessly.



The (I think) relevant parts for the config on the 2nd router with the 
tunnel are:


ipv4 table master4;
ipv6 table master6;

mpls table mtab;
mpls domain mdom {
    label range bgprange { start 2000; length 1000; };
}
vpn4 table vpntab4;
vpn6 table vpntab6;

ipv4 table t_as207781_ipv4;
ipv6 table t_as207781_ipv6;

protocol device
{
    scan time 5;
}

protocol kernel
{
    scan time 60;
    mpls { table mtab; export all; };
}

protocol kernel
{
    scan time 30; <- this timer causes BIRD to re-export the whole 
table over and over again

    learn;

    vrf "vrf-as207781";
    kernel table 1;

    ipv6 {
    table t_as207781_ipv6;
    import none;
    export accept;
    };
}

protocol ospf v3 o_mclnet_ipv6 {
    vrf default;

    ipv6 {
    import all;
    export where source ~ [ RTS_DEVICE, RTS_STATIC ];
    };

    area 0 {
    interface "l2tp*" {
    hello 1;
    type pointopoint;
    };
    interface "br*", "dummy*" {
    stub;
    };
    };
}

protocol l3vpn m_as207781 {
    vrf "vrf-as207781";
    ipv4 { table t_as207781_ipv4;  };
    ipv6 { table t_as207781_ipv6;  };
    vpn4 { table vpntab4; };
    vpn6 { table vpntab6; };
    mpls { label policy vrf; };

    rd 64512:1;
    import target [(rt, 64512, 1)];
    export target [(rt, 64512, 1)];
}

protocol bgp i_lotor {

    mpls { label policy aggregate; };
    vpn4 mpls { table vpntab4; import all; export all; extended 
next hop on; next hop self on; };
    vpn6 mpls { table vpntab6; import all; export all; extended 
next hop on; next hop self on; };

    local fd00::3 as 64512;
    neighbor fd00::2 as 64512;
}

Kind regards,

Marcel Menzel