bgpd: bmp: don't prepend local-AS to AS_PATH in BMP updates - #21815
Conversation
Greptile SummaryFixes a long-standing correctness bug in BMP Route Monitoring: Confidence Score: 4/5Safe to merge; the fix is correct, all callers are updated, and memory management is unaffected. Only P2 findings (a slightly inaccurate inline comment). Core logic, memory ownership, and the for_bmp guard are all correct. Score held at 4 rather than 5 due to the minor comment inaccuracy. bgpd/bgp_attr.c β the new inline comment at line ~5363 overstates that Adj-RIB-In is the only BMP mode FRR supports. Important Files Changed
Sequence DiagramsequenceDiagram
participant Peer as BGP Peer (AS 65502)
participant FRR as FRR Router (AS 65501)
participant BMP as BMP Collector
Peer->>FRR: UPDATE [AS_PATH=65502] prefix=172.31.0.15/32
FRR->>FRR: Store attr->aspath = [65502]
note over FRR,BMP: Before fix: bmp_update() called bgp_packet_attribute()<br/>with no for_bmp flag β eBGP path applied local-AS prepend
FRR--xBMP: BMP Route Monitor [AS_PATH=65501 65502] β
note over FRR,BMP: After fix: bmp_update() passes for_bmp=true
FRR->>BMP: BMP Route Monitor [AS_PATH=65502] β
(as stored)
note over FRR: Outbound BGP UPDATE to other peers unchanged
FRR->>Peer: UPDATE [AS_PATH=65501 65502] (for_bmp=false, normal eBGP prepend)
Prompt To Fix All With AIThis is a comment left during a code review.
Path: bgpd/bgp_attr.c
Line: 5363-5371
Comment:
**Inaccurate comment: FRR already emits loc-rib messages**
The comment says "BMP Adj-RIB-In monitoring (the only BMP mode FRR currently supports)", but the test-suite changes in this very PR update expected JSON for `loc-rib`, `pre-policy`, and `post-policy` modes β meaning FRR already supports at least three BMP table types. Calling it "the only BMP mode" is misleading to future readers and may cause confusion when RFC 8671 Adj-RIB-Out work begins.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "bgpd: bmp: don't prepend local-AS to AS_..." | Re-trigger Greptile |
435b95d to
a305dba
Compare
|
I see two separate bug fixes, at the very least. Why is this not two commits? I would also like to see discussion from some of our bgp operators on what they want to do here since this will be a non-backwards compatible change to what is delivered and we need to ensure that this is thought out and that operators have a path forward that makes sense to them. |
Thanks for looking @donaldsharp . Appreciate the quick feedback. You are right. While fixing the BMP local-as issue, I had to fix the 32-bit ASN encoding issue in order for the modified tests to pass. So there are exactly two fixes here. I can split this now. Should have done it like that to begin with, but the local-as path tests in the second PR wouldn't pass without the first change, and I wasn't sure what's the strategy for posting stacked PRs (first time contributor here). About the backward compatibility concern, is there any action item on me? |
|
I just think I want to discuss this in next weeks tech meeting. We should go over it because it's a new PR that came in during the week. Feel free to join and have the discussion with us. |
a305dba to
69a7b2c
Compare
ton31337
left a comment
There was a problem hiding this comment.
Please fix frrbot styling issues.
4bc3402 to
c5dcc07
Compare
Done. Thanks. |
c5dcc07 to
89b89c3
Compare
Add FRR patch backporting the BMP local-AS fix from upstream PR FRRouting/frr#21815 to the FRR 10.5.1 base in this repo. See the patch file for the full commit message. Patch numbered 0108 (master had reached 0107 since the original 0106 number was chosen).
|
Happy to see this option go in. I was just about to file a bug report on the same issue, about prepending local AS to BMP monitor messages. I concur with the reading in RFC7854 4271 and 9069. This flag addition should help turn off that prepend behavior for BMP monitor. |
Add FRR patch backporting the BMP local-AS fix from upstream PR FRRouting/frr#21815 to the FRR 10.5.1 base in this repo. See the patch file for the full commit message. Patch numbered 0108 (master had reached 0107 since the original 0106 number was chosen). Signed-off-by: Kalash Nainwal <kalash@nexthop.ai>
|
@kalash-nexthop what do you think by adding a new configuration knob to control this (append vs. no-append)? Then we don't need any changes once we have adj-rib-out. |
@ton31337 A new config knob would still mean either rib-in policy behavior would be wrong or the future rib-out behavior (based on operator's configured value). IMHO we shouldn't leave the behavior here to operator preference. The current single-arg design already accommodates the future Adj-RIB-Out cleanly, as a future That said, the arg |
|
Just to concur, it looks like @kalash-nexthop has everything correct for what we would expect. I like the flag rename suggestion, but any name is fine in my book. |
|
Please squash these two commits (styling fix + actual fix) into a single one. |
89b89c3 to
d1fce47
Compare
Done. Thanks @ton31337 |
d1fce47 to
6b1cda1
Compare
0b3dbb3 to
43047cb
Compare
|
Three CI runs in a row have failed on different unrelated tests (bgp_soo, then ospf_rfc4222_dscp, then bgp_conditional_advertisement_track_peer). The same failures are hitting other open PRs β #22008, #21992, #21967, #21943 on bgp_soo, and #22009 on bgp_conditional_advertisement_track_peer. This seems to be a CI/test-side flakiness. CI used to pass earlier on this PR before I rebased today. Any advise @ton31337 ? |
|
bgp soo & friends should have been fixed in master already, so let's see what we have right now. |
|
Quick update from talking with other BMP people: nobody seems to be entirely sure what the behavior should be in this case, and there is very little practical data. |
I'd like to push back on this comment. People at CAIDA noticed this bug at the point it was introduced (years ago). I myself only recently saw the impact when checking on some of the data that RouteViews generates. So there is no confusion on our part. We are seeing the impact of the prepend bug in the data in our system currently. Let me help you understand a little bit. You have a monitor. It collects BMP Monitor data. It is not pushing traffic around. Adding the asnum of the monitor in the pre-policy, post-policy-in, or loc-rib, as if it were part of a BGP UPDATE msg that came to the peer, makes no sense. So I would again say we are hopeful that the patch in this commit, or the equivalent, goes through. adj-RIB-out is the only place you could argue for a prepend. And we're not talking about that case here. |
pipeline passes now. |
I poked some implementers (and one BMP operator) and you see the result above [for Adj-RIB-out. See end of this comment.] The response was basically "hmm, we never thought about that", to the degree that they didn't even know what their code does. No more and no less. I'm sad to hear that this is causing issues for your data collection.
Sigh. The tone here is rather condescending. I know who you are and respect your work, so I'm ignoring that. Still, it's not helpful for the discussion. FYI: I wrote the original BMP code in FRR. I'm not perfect, my code has bugs, this is one of them. I do, however, understand well enough what BMP is, does, and how it's used.
You might've noticed I haven't previously commented on this PR. My going around asking people was triggered by the discussion of this PR on our weekly tech call. My understanding from the call was that this PR is for Adj-RIB-out. Funnily enough, this miscommunication might've happened because for Adj-RIB-in I could've answered that right there on the call. It made no sense to me that there'd be a discussion on that. Anyway. I'm not sure what the uncertainty was that triggered the discussion on the call, I'm going to assume it's resolved. I do hope we didn't lose a bug report about this (I couldn't find one), but if the CAIDA people knew about this for years and just didn't report it, that's⦠unfortunate. We can't fix bugs we're not aware of. |
No issues here. We are nothing but appreciative for all the hard work on the project. Sorry if that came across as condescending. I was just trying to be brief, and as clear as I could be to avoid any confusion about the thread topic. With the fix being so close to merge, I wanted to make sure that it was clear that there really are people who know what the issue is, and have a use for this particular fix. Again, we appreciate all the hard work here. |
|
Hi @eqvinox, I appreciate the time and effort you spent in soliciting feedback from other bmp folks on this. From our (Nexthop systems) side, this issue is caught while executing a customer testcase, who clearly want the behavior of not prepending local-as to these BMP updates. Sadly, the RFC doesn't explicitly mention this the datapoint that I have here is anecdotal in that sense. |
|
@kalash-nexthop you said you'd split it in 2 commits, are you still going to do that? Personally it's below my threshold for caring since the 32bit fix is 1 code line, but you did say yes you'll do that π |
No worries. If anything I was just making sure we don't get a slow creep in the community at large, better to say something on a tiny thing vs. having a big deal later after tone's drifted π
Thank you! Like I said I appreciate and respect your work as well! Fun fact: I'm writing this while attending RIPE 92, trying to make sure we keep up with the needs the DFZ operator community. The DFZ is hard enough to understand with all the monitoring and analysis tools we have, without them we'd be blundering around in the dark. |
@eqvinox Sorry I couldn't do it earlier. I didn't explain the issue I hit when I was trying to split this (although I briefly mentioned earlier in this PR that without the 32bit asn I couldn't get the CI for local-as related change to pass). When I applied just the local-AS hunks, bgp_bmp topotests failed; adding the 32-bit force made them pass. My best guess was an interaction with the A-flag-never-set bug in FRR's BMP per-peer header during peer-flap triggered in router id change test. Maybe the test was flaky and folding 32bit asn change in this PR itself was indirectly making it go away. Shall I try to split the PR and see if the topotests pass? Asking again as I saw two approvals on this already. |
commit != PR, looks like we had a misunderstanding :) - you can just split it into 2 commits and leave it in the same PR. |
43047cb to
1d665cf
Compare
Ah right, thanks for clarifying. Split this into two commits now. |
1d665cf to
777af0e
Compare
BMP Route Monitoring messages for monitored routes carried an AS_PATH
with the local AS prepended, as if the route were being re-advertised
outbound. Observed with a peer in AS 40001 advertising 100.100.100.1/32
to a router in AS 40002:
"as_path":[40002,40001], "as_path_count":2, "peer_asn":40001
The collector expected AS_PATH=[40001] -- the value as received from
the peer -- but saw [40002,40001] because the local AS was prepended on
its way out to the collector.
Root cause: bmp_update() in bgp_bmp.c reuses bgp_packet_attribute(),
the outbound attribute serializer, which performs peer-specific
outbound transformations on AS_PATH (prepend peer->local_as for eBGP,
confed-seq handling, change-local-as). These are correct for sending
an UPDATE to a peer, but the BMP modes FRR currently emits
(pre-policy / post-policy Adj-RIB-In and Loc-RIB) feed receive-side
stored attributes into the serializer and must report them as stored.
Fix: add a bool for_bmp parameter to bgp_packet_attribute(). When
true, skip the peer-sort-based AS_PATH transformations and emit
attr->aspath as-is (no local-AS prepend, no confed-seq manipulation,
no change-local-as).
bmp_update() passes for_bmp=true. The outbound callers in
bgp_updgrp_packet.c pass false to keep their current behaviour.
Also update the bgp_bmp topotest expected JSON files for all three
modes: previously they encoded the prepended local-AS ("65501 65502"
where 65501 is the local AS); now they expect the raw AS_PATH "65502"
as received from the peer in AS 65502.
Signed-off-by: Kalash Nainwal <kalash@nexthop.ai>
777af0e to
65f5512
Compare
BMP route-monitoring messages need a stable AS_PATH ASN encoding width:
the per-peer header's A flag (RFC 7854 4.2) tells the collector whether
AS_PATH ASNs are 2-byte or 4-byte. FRR's BMP code never sets the A flag
(only V and L are ever set in bgp_bmp.c), so every BMP message
advertises A=0 (4-byte AS_PATH format).
However, the AS_PATH bytes that bgp_packet_attribute() actually writes
to the wire are governed by use32bit, which derives from the peer's AS4
capability state:
use32bit = CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) &&
CHECK_FLAG(peer->cap, PEER_CAP_AS4_ADV);
peer->cap can be transiently cleared while a session re-establishes
(e.g. during a peer/VRF flap or a router-id change). If a BMP
route-monitoring emit happens in that window, use32bit becomes false,
FRR writes 2-byte ASN bytes on the wire, but the per-peer header still
claims A=0 (4-byte format). The collector decodes 2-byte bytes as
4-byte, the bytes misalign, and parsing fails -- often dropping
subsequent peer-up / peer-down / route-monitor messages until the BMP
session is re-established.
Fix: force use32bit=true whenever for_bmp is set, decoupling BMP
emission from peer->cap state. RFC 9069 5.4.1 in fact requires 4-byte
ASN encoding for Loc-RIB BMP messages, and RFC 7854 4.2 allows a BMP
speaker to "reformat all AS_PATH information into a 4-byte format
regardless of how it was received from the peer." As a side effect this
also suppresses the AS4_PATH backward-compat attribute (send_as4_path
is only set when use32bit is false), which BMP collectors don't need.
Signed-off-by: Kalash Nainwal <kalash@nexthop.ai>
65f5512 to
4726014
Compare
|
Thanks a lot @eqvinox ! |
Add FRR patch backporting the BMP local-AS fix from upstream FRR PR FRRouting/frr#21815 (merged) to the FRR base in this repo. See the patch file for the full commit message. Signed-off-by: Kalash Nainwal <kalash@nexthop.ai>
Add FRR patch backporting the BMP local-AS fix from upstream FRR PR FRRouting/frr#21815 (merged) to the FRR base in this repo. See the patch file for the full commit message. Signed-off-by: Kalash Nainwal <kalash@nexthop.ai>
bgpd: bmp: don't prepend local-AS to AS_PATH in BMP updates
BMP Route Monitoring messages for monitored routes carried an AS_PATH
with the local AS prepended, as if the route were being re-advertised
outbound. Observed with a peer in AS 40001 advertising 100.100.100.1/32
to a router in AS 40002:
The collector expected
AS_PATH=[40001]-- the value as received fromthe peer -- but saw
[40002,40001]because the local AS was prependedon its way out to the collector.
Root cause:
bmp_update()inbgp_bmp.creusesbgp_packet_attribute(),the outbound attribute serializer, which performs peer-specific outbound
transformations on AS_PATH (prepend
peer->local_asfor eBGP, confed-seqhandling, change-local-as). These are correct for sending an UPDATE to
a peer, but BMP is a reporting channel -- pre-policy, post-policy, and
loc-rib must all emit the AS_PATH as stored (received / selected),
never with the outbound local-AS prepended.
Fix: add a
bool for_bmpparameter tobgp_packet_attribute(). Whentrue:
Skip the peer-sort-based AS_PATH transformations and emit
attr->aspathas-is (no local-AS prepend, no confed-seqmanipulation).
Force 32-bit ASN encoding regardless of the peer's AS4 capability
state. This is needed for loc-rib re-dumps after a VRF/peer flap:
peer->capcan be momentarily cleared while the sessionrenegotiates, which would otherwise cause
aspath_put()to emit16-bit AS_PATH segments. Modern BMP collectors always parse ASNs as
32-bit, so a 16-bit segment produces a byte-level parse error and
the collector disconnects, losing all subsequent peer-up / peer-down
/ route-monitor messages.
bmp_update()passesfor_bmp=true(covers pre-policy, post-policy,and loc-rib). The outbound callers in
bgp_updgrp_packet.cpass falseto keep their current behaviour.
Also update the
bgp_bmptopotest expected JSON files for all threemodes: previously they encoded the prepended local-AS (
"65501 65502"where 65501 is the local AS); now they expect the raw AS_PATH
"65502"as received from the peer in AS 65502.