-
Notifications
You must be signed in to change notification settings - Fork 1.4k
bgp: Support multiple labels in BGP-LU #19961
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
We should eventually add CONFDATE (a deprecation for remoteLabel for one year, that would be quite enough). |
|
please put more verbiage in the commit message besides |
40a900b to
f75c8bd
Compare
|
@donaldsharp I've updated commit message. If even more verbose commit message is needed (or any other changes), please say. |
f75c8bd to
e56fe22
Compare
|
I've also updated message for commit with test. @ton31337 thanks for your answer, should I add Near the field in this PR? |
|
Yes, above |
e56fe22 to
c773136
Compare
|
@ton31337 Done, thanks. |
|
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
c773136 to
e7b2644
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code changes look good overall:
- Both sending and receiving of UPDATE messages with multiple labels is supported
- Take care of BOS value being appropriately set in a case of single or multiple labels.( Some implicit setting BoS also exists which should have been verified in testing)
- Correctly calculates the maximum possible number of labels and required size for labels to write in the stream
- Also, provide backward compatibility for encode_label() used by Mpls VPN.
Few corrections and improvements have been suggested under particular line of code in individual comments
hedrok
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ritika0313 Thank you for thorough review. I've replied to all your comments and updated PR.
e7b2644 to
5807236
Compare
tests/topotests/bgp_lu_multiple_labels/test_bgp_lu_multiple_labels.py
Outdated
Show resolved
Hide resolved
tests/topotests/bgp_lu_multiple_labels/test_bgp_lu_multiple_labels.py
Outdated
Show resolved
Hide resolved
|
|
||
| sleep(5) | ||
|
|
||
| stdout.write("announce route 2001:db8:100::/64 next-hop fc00::2 label [777 10006]\n") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we just announce these immediately without using a Python script (in the ExaBGP config directly)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thank you, I experimented a little more and it works now - of course it is simpler this way.
And now 5 seconds less sleep :)
lib/stream.c
Outdated
| if (STREAM_WRITEABLE(s) < (psize_with_addpath + 3)) { | ||
| if (p->prefixlen + MPLS_LABEL_LEN_BYTES * 8 * num_labels >= 256) { | ||
| num_labels = (256 - p->prefixlen) / 8 / MPLS_LABEL_LEN_BYTES; | ||
| zlog_info("%s: Ignoring extra labels, can fit only %d in BGP-LU message with prefixlen %d", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be a warning instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thank you.
hedrok
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated according to @ton31337 comments:
- Replaced BGP_LABEL_BYTES -> MPLS_LABEL_LEN_BYTES globally not to have two constants
- Chaned info to warning in case
stream_put_labeled_prefixcan't put so many labels. - Increased all timeouts in topotest to minimum 15 seconds.
- Simplified ExaBGP configuration in topotest
I rebase my changes to master and use fixup of commits so that there are only two commits: one with actual changes, other one with tests. If any of reviewers prefers new commits for new changes and no history rewriting for easier review - please say, I'll do it this way then.
lib/stream.c
Outdated
| if (STREAM_WRITEABLE(s) < (psize_with_addpath + 3)) { | ||
| if (p->prefixlen + MPLS_LABEL_LEN_BYTES * 8 * num_labels >= 256) { | ||
| num_labels = (256 - p->prefixlen) / 8 / MPLS_LABEL_LEN_BYTES; | ||
| zlog_info("%s: Ignoring extra labels, can fit only %d in BGP-LU message with prefixlen %d", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thank you.
tests/topotests/bgp_lu_multiple_labels/test_bgp_lu_multiple_labels.py
Outdated
Show resolved
Hide resolved
tests/topotests/bgp_lu_multiple_labels/test_bgp_lu_multiple_labels.py
Outdated
Show resolved
Hide resolved
|
|
||
| sleep(5) | ||
|
|
||
| stdout.write("announce route 2001:db8:100::/64 next-hop fc00::2 label [777 10006]\n") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thank you, I experimented a little more and it works now - of course it is simpler this way.
And now 5 seconds less sleep :)
5807236 to
a90f728
Compare
ton31337
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
ritika0313
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good
a90f728 to
00fe1bc
Compare
|
@ton31337 thank you for approve, I've added one small change as @ritika0313 has a valid point: in hypothetic case of receiving more labels than BGP_MAX_LABELS I must set BOS for the last one we store. This is the only change, here is full diff: diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
index 7046c61ff9..09a732e11e 100644
--- a/bgpd/bgp_label.c
+++ b/bgpd/bgp_label.c
@@ -459,6 +459,7 @@ static int bgp_nlri_get_labels(struct peer *peer, uint8_t *pnt, uint8_t plen, mp
if (label_depth > BGP_MAX_LABELS) {
*num_labels = BGP_MAX_LABELS;
+ label_set_bos(&labels[*num_labels - 1]);
zlog_info("%pBP rcvd UPDATE with label stack %d deep, using only first %d labels",
peer, label_depth, BGP_MAX_LABELS);
}
diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h
index b8e48cefaf..18967cb805 100644
--- a/bgpd/bgp_label.h
+++ b/bgpd/bgp_label.h
@@ -123,4 +123,12 @@ static inline uint8_t label_bos(mpls_label_t *label)
return (t[2] & 0x01);
};
+/* Set BOS to 1 */
+static inline void label_set_bos(mpls_label_t *label)
+{
+ uint8_t *t = (uint8_t *)label;
+
+ t[2] |= 0x01;
+}
+
#endif /* _BGP_LABEL_H */
|
dmytroshytyi-6WIND
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, Thanks
4666f4d to
55358dd
Compare
55358dd to
fe68141
Compare
lib/stream.c
Outdated
| int stream_put_labeled_prefix(struct stream *s, const struct prefix *p, | ||
| mpls_label_t *label, bool addpath_capable, | ||
| uint32_t addpath_tx_id) | ||
| int stream_put_labeled_prefix(struct stream *s, const struct prefix *p, mpls_label_t *label, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this in lib/ - it sure looks as if it's a bgp-protocol function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logically I'm sure it should be in bgp code and it is used only once in bgpd/bgp_attr.c.
The function uses a lot of macro from lib/stream.c that I had to move to lib/stream.h for it to work.
I've done the move in separate commit for easier review and removal if not needed: bb14416
Please say whether this move is ok - if so, I'll squash the commit with main one and will be able to make two small refactorings:
- Remove introduced
MPLS_LABEL_LEN_BYTESand get backBGP_LABEL_BYTES- I've added new constant only because it was needed in this function that is inlib/stream.c, where bgp constant is unavailable. - Make use of
label_set_bosinstead ofmpls_lse_decode+mpls_lse_encode
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, ouch, I see what you mean - no, you should leave that change out.
the thing that's awkward about the lib/stream api is that it does all that detailed byte-building work. could we move the bit/byte code into bgp, so that bgp constructs a buffer with its own logic, and then uses just a vanilla stream api to add the bgp buffer? in any case, that's not really a responsibility of yours, for this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great idea - it allowed me to implement two small refactorings mentioned earlier, merge stream_bgp_put_labeled_prefix and stream_put_prefix_addpath, overall code became much cleaner.
I tried my best not to introduced issues - now I've changed function that writes any BGP NLRI to stream... At least I hope that if I broke something topotests shoulds catch that, as it is core functionality, so I'm waiting for CI verdict with big interest...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, I really sort of meant it when I said "you should leave that change out".
again, just let's see about getting the BGP-LU pieces through, and then if you want to adjust the stream code, that would be better as a separate PR (potentially of interest to a different set of reviewers, for example)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I thought that "could we move the bit/byte code into bgp" was suggestion for action :)
Reverted, but left small preparations for this refactoring as I liked this change and I plan to create separate PR with it as soon as this PR is merged. And yes, it would be better to review it with extreme attention.
What I left is:
+/* TODO Move out label-specific logic to bgpd, there BGP_LABEL_BYTES is already defined */
+#define BGP_LABEL_BYTES 3
In lib/stream.c - hope it is not a problem, it will make refactoring easier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the diff here is still ... large? it'd be clearer just to get the bgp parts in, and then look at the lib/stream part.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok.
I've reverted everything in lib/stream.*, reverted bgp_packet_mpattr_prefix_size (as now it is possible to send only one label) and updated bgp_packet_mpattr_prefix accordingly.
So now multiple labels won't work properly when use_local_label is false in bgp_adv_label (basically when PEER_FLAG_FORCE_NEXTHOP_SELF or PEER_FLAG_NEXTHOP_UNCHANGED are applied) - in such case only top label will be retransmitted and a warning issued.
Simpler case of just receiving multiple labels still works, which is covered by test.
| &exp, &bos); | ||
| uint8_t i; | ||
|
|
||
| api_nh->label_num = num_labels; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
must validate the number of labels against the fixed-size array in the zapi nexthop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/mpls.h
#define MPLS_MAX_LABELS 16lib/zclient.h
struct zapi_nexthop {
...
mpls_label_t labels[MPLS_MAX_LABELS];And in bgp I've added theoretical maximum:
bgpd/bgp_label.h
#define BGP_MAX_LABELS 10Of course I don't mind checking anyway, should I add something like
static_assert(BGP_MAX_LABELS <= MPLS_MAX_LABELS && sizeof(api_nh->labels) / sizeof(api_nh->labels[0]) == MPLS_MAX_LABELS,
"Code expects BGP_MAX_LABELS <= MPLS_MAX_LABELS and api_nh->labels is array of MPLS_MAX_LABELS elements. If that changes, please adapt code below");
To guard against possible changes of these constants and that api_nh->labels is array of MPLS_MAX_LABELS elements?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather not have an assert - there's no real need to crash. I'd just like to see, in general, that the destination array limit be respected/checked during the iteration. An assumption about the code today may not always be correct in the future, and it'll always be safe to copy only as many values as there are destination cells?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I've just made obvious change:
if (api_nh->label_num > MPLS_MAX_LABELS) {
zlog_warn("%s: too many labels provided for zebra (%d), copying first %d",
__func__, num_labels, MPLS_MAX_LABELS);
api_nh->label_num = MPLS_MAX_LABELS;
}But also added static_assert I've suggested above (after battle with checkpatch.sh and enduring awful in my personal opinion format changes from git clang-format).
I've suggested static_assert - compilation error, not crash.
I think this way message will be provided to the developer who tried to change these preconditions right away during compilation time and it will be much more obvious then losing some labels and warning log...
When changing BGP_MAX_LABELS to 20 I get during compilation:
In file included from ./lib/zebra.h:74,
from bgpd/bgp_zebra.c:7:
bgpd/bgp_zebra.c: In function 'bgp_zebra_announce_parse_nexthop':
./lib/assert/assert.h:30:23: error: static assertion failed: "Code expects BGP_MAX_LABELS <= MPLS_MAX_LABELS and api_nh->labels is an array of MPLS_MAX_LABELS elements. If that changes, please adapt code below"
30 | #define static_assert _Static_assert
| ^~~~~~~~~~~~~~
bgpd/bgp_zebra.c:1425:33: note: in expansion of macro 'static_assert'
1425 | static_assert(BGP_MAX_LABELS <= MPLS_MAX_LABELS &&
| ^~~~~~~~~~~~~
Of course I can remove this if you think it is a bad idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that section just makes the code harder to read; I'm not sure we need to couple bgp and the FRR zapi library, really.
I think it's better and clearer just to ensure we don't overrun the target/destination array.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🫡 Sorry for long discussion. Changed to just checking destination array size, removed all static_assert part:
int max_elements = sizeof(api_nh->labels) /
sizeof(api_nh->labels[0]);
api_nh->label_num = num_labels;
if (api_nh->label_num > max_elements) {
zlog_warn("%s: too many labels provided for zebra (%d), copying first %d",
__func__, num_labels, max_elements);
api_nh->label_num = max_elements;
}
for (i = 0; i < api_nh->label_num; i++) {fe68141 to
bb14416
Compare
bb14416 to
5a5a172
Compare
24d211d to
910111f
Compare
|
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
910111f to
a6233a3
Compare
tools/checkpatch.pl
Outdated
| my $to = $4; | ||
| my $newcomp = $comp; | ||
| if ($lead !~ /(?:$Operators|\.)\s*$/ && | ||
| $to !~ /^(?:Constant|[A-Z_][A-Z0-9_]*)$/ && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, no - don't try to extend this PR to include a tools change too. if you want to propose something like this, go ahead and put it in its own PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, will create separate PR. I just needed this to pass checkpatch.sh check so risked adding here. Don't need it anymore as I've removed static_assert.
a6233a3 to
74f496f
Compare
74f496f to
34a4e86
Compare
Updated behaviour for SAFI_LABELED_UNICAST to support multiple labels: * Change BGP_MAX_LABELS 2 -> 10 (maximum possible number of labels for BGP-LU), previously for SAFI_LABELED_UNICAST only one label was supported * Save all labels when receiving an update event in `bgp_nlri_get_labels`, send them all to zebra in `bgp_zebra_announce_parse_nexthop` One of uses of multiple labels is SR-TE with BGP-LU. Resolves FRRouting#19506 Signed-off-by: Kyrylo Yatsenko <hedrok@gmail.com>
Announce three routes with label stacks 777/10006, 90, 11/22/33/44/55, check that `show bgp ipv6 PREFIX json` has proper labels in `remoteLabels`. Test for issue FRRouting#19506 Signed-off-by: Kyrylo Yatsenko <hedrok@gmail.com>
34a4e86 to
a2cdb46
Compare
|
🥳 🎉 Thanks to everybody, this is the most reviewed PR in my life :) |
Add support for multiple labels in BGP-LU + topological test using ExaBGP for that.
Absolute possible maximum number of labels according to RFC 3017/RFC 8277 (see comment to BGP_MAX_LABELS) is supported: max 10 labels.
Open questions:
I've added 8*3=24 bytes per struct
bgp_labels- is that is a problem, should I make it dynamic likempls_label_stack?[answered] Not to break backward compatibility in json output of
route_vty_out_detail(command likeshow ip bgp 33.10.10.0/30 json), I've addedremoteLabelswith array of labels, but leftremoteLabelwith top label in stack intact. Should I instead remove this duplicate field and change all topotests accordingly? (@ton31337 suggested to use CONFDATE check to issue warning in a year to remind thatremoteLabelremoval is needed)Resolves #19506