Skip to content

bgpd: Implement BGPID next-hop characteristic #19349

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

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 62 additions & 37 deletions bgpd/bgp_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -700,14 +700,19 @@ static uint32_t bgp_nhc_hash_key_make(const void *p)
{
const struct bgp_nhc *nhc = p;
uint32_t key = 0;
struct bgp_nhc_tlv *tlv;

key = jhash_3words(nhc->afi, nhc->safi, nhc->nh_length, key);
key = jhash_1word(nhc->tlvs_length, key);
key = jhash(&nhc->nh_ipv4, IPV4_MAX_BYTELEN, key);
key = jhash(&nhc->nh_ipv6, IPV6_MAX_BYTELEN, key);

if (nhc->tlvs)
key = jhash(nhc->tlvs, nhc->tlvs_length, key);
if (nhc->tlvs) {
for (tlv = nhc->tlvs; tlv; tlv = tlv->next) {
key = jhash_2words(tlv->code, tlv->length, key);
key = jhash(tlv->value, tlv->length, key);
}
}

return key;
}
Expand Down Expand Up @@ -3640,16 +3645,18 @@ static int bgp_attr_nhc(struct bgp_attr_parser_args *args)
iana_safi_t pkt_safi;
safi_t safi;
struct stream *s = BGP_INPUT(peer);
struct bgp_nhc *nhc;
struct bgp_nhc *nhc = bgp_attr_get_nhc(attr);
uint16_t tlv_code;
uint16_t tlv_length;
struct bgp_nhc_tlv *tlv;
uint8_t nh_length;

if (peer->discard_attrs[args->type] || peer->withdraw_attrs[args->type])
goto nhc_ignore;

if (length < BGP_NHC_MIN_LEN) {
zlog_err("%pBP rcvd BGP NHC attribute length is too short: %d", peer, length);
zlog_err("%pBP rcvd BGP NHC attribute length is too short: %d, expected minimum %d",
peer, length, BGP_NHC_MIN_LEN);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total);
}

Expand All @@ -3667,34 +3674,38 @@ static int bgp_attr_nhc(struct bgp_attr_parser_args *args)
zlog_debug("%pBP rcvd BGP NHC attribute with length %d for afi %s, safi %s", peer,
length, iana_afi2str(pkt_afi), iana_safi2str(pkt_safi));

nhc = XCALLOC(MTYPE_BGP_NHC, sizeof(struct bgp_nhc));
nhc->afi = afi;
nhc->safi = safi;
nhc->nh_length = stream_getc(s);
nh_length = stream_getc(s);

/* If Next-hop is IPv6, we should check if we are not out of bound too */
if (nhc->nh_length == BGP_ATTR_NHLEN_IPV6_GLOBAL) {
if (nh_length == BGP_ATTR_NHLEN_IPV6_GLOBAL) {
if (length < BGP_NHC_MIN_IPV6_LEN) {
zlog_err("%pBP rcvd BGP NHC attribute length is too short: %d", peer,
length);
zlog_err("%pBP rcvd BGP NHC attribute length is too short: %d, expected minimum %d",
peer, length, BGP_NHC_MIN_IPV6_LEN);
bgp_nhc_free(nhc);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total);
}
}

/* Next-hop length should be either 4 or 16 */
if (nhc->nh_length != BGP_ATTR_NHLEN_IPV4 && nhc->nh_length != BGP_ATTR_NHLEN_IPV6_GLOBAL) {
zlog_err("%pBP rcvd wrong next-hop length, %d, in NHC", peer, nhc->nh_length);
if (nh_length != BGP_ATTR_NHLEN_IPV4 && nh_length != BGP_ATTR_NHLEN_IPV6_GLOBAL) {
zlog_err("%pBP rcvd wrong next-hop length, %d, in NHC", peer, nh_length);
bgp_nhc_free(nhc);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, args->total);
}

if (!nhc)
nhc = XCALLOC(MTYPE_BGP_NHC, sizeof(struct bgp_nhc));

nhc->afi = afi;
nhc->safi = safi;
nhc->nh_length = nh_length;

length -= 4; /* AFI(2) + SAFI(1) + Next-hop length(1) */

if (nhc->nh_length == BGP_ATTR_NHLEN_IPV4) {
if (nh_length == BGP_ATTR_NHLEN_IPV4) {
stream_get(&nhc->nh_ipv4, s, IPV4_MAX_BYTELEN);
length -= IPV4_MAX_BYTELEN;
} else if (nhc->nh_length == BGP_ATTR_NHLEN_IPV6_GLOBAL) {
} else if (nh_length == BGP_ATTR_NHLEN_IPV6_GLOBAL) {
stream_get(&nhc->nh_ipv6, s, IPV6_MAX_BYTELEN);
length -= IPV6_MAX_BYTELEN;
if (IN6_IS_ADDR_LINKLOCAL(&nhc->nh_ipv6)) {
Expand Down Expand Up @@ -3750,9 +3761,7 @@ static int bgp_attr_nhc(struct bgp_attr_parser_args *args)

/* draft-wang-idr-next-next-hop-nodes */
if (tlv->code == BGP_ATTR_NHC_TLV_NNHN) {
uint16_t len = tlv->length;

if (len % IPV4_MAX_BYTELEN != 0) {
if (tlv->length % IPV4_MAX_BYTELEN != 0) {
zlog_err("%pBP rcvd BGP NHC (NNHN TLV) length %d not a multiple of %d",
peer, tlv->length, IPV4_MAX_BYTELEN);
bgp_nhc_free(nhc);
Expand All @@ -3762,12 +3771,8 @@ static int bgp_attr_nhc(struct bgp_attr_parser_args *args)
}

found = bgp_nhc_tlv_find(nhc, tlv_code);
if (found) {
nhc->tlvs_length -= found->length + BGP_NHC_TLV_MIN_LEN;
bgp_nhc_tlv_free(found);
}

bgp_nhc_tlv_add(nhc, tlv);
if (!found)
bgp_nhc_tlv_add(nhc, tlv);

length -= tlv_length + BGP_NHC_TLV_MIN_LEN;
}
Expand Down Expand Up @@ -4617,19 +4622,19 @@ static void bgp_packet_nhc(struct stream *s, struct peer *peer, afi_t afi, safi_
afi_t nh_afi;
struct bgp_path_info *exists;
uint16_t total;
struct bgp_nhc *nhc = bgp_attr_get_nhc(attr);
const struct prefix *prefix = NULL;

if (!bpi)
return;

total = bgp_path_info_mpath_count(bpi) * IPV4_MAX_BYTELEN;

/* NHC now supports only draft-wang-idr-next-next-hop-nodes, thus
* do not sent NHC attribute if the path is not multipath or self
* originated.
*/
if (bpi->peer == bpi->peer->bgp->peer_self || bgp_path_info_mpath_count(bpi) < 2)
if (bgp_path_info_mpath_count(bpi) < 2 && !nhc)
return;

prefix = bgp_dest_get_prefix(bpi->net);

total = bgp_path_info_mpath_count(bpi) * IPV4_MAX_BYTELEN;

stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_NHC);
sizep = stream_get_endp(s);
Expand Down Expand Up @@ -4660,15 +4665,35 @@ static void bgp_packet_nhc(struct stream *s, struct peer *peer, afi_t afi, safi_
/* Put TLVs */

/* Begin NNHN TLV */
stream_putw(s, BGP_ATTR_NHC_TLV_NNHN);
stream_putw(s, total);
stream_put_ipv4(s, bpi->peer->remote_id.s_addr);
if (bgp_path_info_mpath_count(bpi) > 1) {
if (bgp_debug_update(peer, NULL, NULL, 1))
zlog_debug("%pBP: Sending NHC TLV (%d) for %pFX", peer,
BGP_ATTR_NHC_TLV_NNHN, prefix);
stream_putw(s, BGP_ATTR_NHC_TLV_NNHN);
stream_putw(s, total);
stream_put_ipv4(s, bpi->peer->remote_id.s_addr);

for (exists = bgp_path_info_mpath_first(bpi); exists;
exists = bgp_path_info_mpath_next(exists))
stream_put_ipv4(s, exists->peer->remote_id.s_addr);
for (exists = bgp_path_info_mpath_first(bpi); exists;
exists = bgp_path_info_mpath_next(exists))
stream_put_ipv4(s, exists->peer->remote_id.s_addr);
}
/* End NNHN TLV */

/* Other TLVs */
if (nhc) {
struct bgp_nhc_tlv *tlv = NULL;

for (tlv = nhc->tlvs; tlv; tlv = tlv->next) {
if (bgp_debug_update(peer, NULL, NULL, 1))
zlog_debug("%pBP: Sending NHC TLV (%u) for %pFX", peer, tlv->code,
prefix);
stream_putw(s, tlv->code);
stream_putw(s, tlv->length);
stream_put(s, tlv->value, tlv->length);
}
}
/* Other TLVs */

stream_putc_at(s, sizep, (stream_get_endp(s) - sizep) - 1);
}

Expand Down
16 changes: 15 additions & 1 deletion bgpd/bgp_nhc.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ void bgp_nhc_tlv_add(struct bgp_nhc *nhc, struct bgp_nhc_tlv *tlv)
nhc->tlvs_length += tlv->length + BGP_NHC_TLV_MIN_LEN;
}

struct bgp_nhc_tlv *bgp_nhc_tlv_new(uint16_t code, uint16_t length, const void *value)
{
struct bgp_nhc_tlv *tlv;

tlv = XCALLOC(MTYPE_BGP_NHC_TLV, sizeof(struct bgp_nhc_tlv) + IPV4_MAX_BYTELEN);
tlv->code = code;
tlv->length = length;
tlv->value = XCALLOC(MTYPE_BGP_NHC_TLV_VAL, length);

memcpy(tlv->value, value, length);

return tlv;
}

struct bgp_nhc_tlv *bgp_nhc_tlv_find(struct bgp_nhc *nhc, uint16_t code)
{
struct bgp_nhc_tlv *tlv = NULL;
Expand All @@ -35,7 +49,7 @@ struct bgp_nhc_tlv *bgp_nhc_tlv_find(struct bgp_nhc *nhc, uint16_t code)
return tlv;
}

return tlv;
return NULL;
}

void bgp_nhc_tlv_free(struct bgp_nhc_tlv *tlv)
Expand Down
3 changes: 3 additions & 0 deletions bgpd/bgp_nhc.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ struct bgp_nhc {
/* TLV values: */
/* draft-wang-idr-next-next-hop-nodes */
#define BGP_ATTR_NHC_TLV_NNHN 2
/* draft-ietf-idr-entropy-label */
#define BGP_ATTR_NHC_TLV_BGPID 3

extern void bgp_nhc_tlv_add(struct bgp_nhc *nhc, struct bgp_nhc_tlv *tlv);
extern struct bgp_nhc_tlv *bgp_nhc_tlv_find(struct bgp_nhc *nhc, uint16_t code);
extern void bgp_nhc_tlv_free(struct bgp_nhc_tlv *tlv);
extern void bgp_nhc_tlvs_free(struct bgp_nhc_tlv *tlv);
extern void bgp_nhc_free(struct bgp_nhc *bnc);
extern struct bgp_nhc_tlv *bgp_nhc_tlv_new(uint16_t code, uint16_t length, const void *value);

#endif /* _FRR_BGP_NHC_H */
36 changes: 33 additions & 3 deletions bgpd/bgp_route.c
Original file line number Diff line number Diff line change
Expand Up @@ -7396,6 +7396,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
uint8_t num_labels = 0;
struct bgp *bgp_nexthop = bgp;
struct bgp_labels labels = {};
struct bgp_nhc_tlv *tlv;
struct bgp_nhc *nhc;
uint8_t nh_length = IPV6_MAX_BYTELEN;

assert(bgp_static);

Expand All @@ -7408,13 +7411,26 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,

bgp_attr_default_set(&attr, bgp, BGP_ORIGIN_IGP);

if (afi == AFI_IP)
nh_length = IPV4_MAX_BYTELEN;

/* NHC */
nhc = XCALLOC(MTYPE_BGP_NHC, sizeof(struct bgp_nhc));
nhc->afi = afi;
nhc->safi = safi;
nhc->nh_length = nh_length;
nhc->tlvs_length = IPV4_MAX_BYTELEN;

tlv = bgp_nhc_tlv_new(BGP_ATTR_NHC_TLV_BGPID, IPV4_MAX_BYTELEN, &bgp->router_id);
bgp_nhc_tlv_add(nhc, tlv);
bgp_attr_set_nhc(&attr, nhc);
/* NHC */

attr.nexthop = bgp_static->igpnexthop;
attr.mp_nexthop_len = nh_length;

bgp_attr_set_med(&attr, bgp_static->igpmetric);

if (afi == AFI_IP)
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;

if (bgp_static->atomic)
SET_FLAG(attr.flag, ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE));

Expand Down Expand Up @@ -12310,6 +12326,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
struct bgp_nhc_tlv *tlv = NULL;

if (nhc) {
if (!json_paths)
vty_out(vty, " Characteristics:\n");

for (tlv = nhc->tlvs; tlv; tlv = tlv->next) {
if (tlv->code == BGP_ATTR_NHC_TLV_NNHN) {
json_object *json_nhc_nnhn = NULL;
Expand All @@ -12333,6 +12352,17 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
if (json_paths)
json_object_object_add(json_path, "nextNextHopNodes",
json_nhc_nnhn);
} else if (tlv->code == BGP_ATTR_NHC_TLV_BGPID) {
struct in_addr router_id;

memcpy(&router_id.s_addr, tlv->value,
sizeof(router_id.s_addr));

if (!json_paths)
vty_out(vty, " BGPID: %pI4\n", &router_id);
else
json_object_string_addf(json_path, "bgpId", "%pI4",
&router_id);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions bgpd/bgp_updgrp_adv.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "bgpd/bgp_updgrp.h"
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_addpath.h"
#include "bgpd/bgp_nhc.h"


/********************
Expand Down
1 change: 1 addition & 0 deletions tests/topotests/bgp_nhc/r1/frr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ int r1-eth1
ip address 10.255.16.1/24
!
router bgp 65001
bgp router-id 10.255.0.1
no bgp ebgp-requires-policy
neighbor 10.255.0.2 timers 1 3
neighbor 10.255.0.2 timers connect 1
Expand Down
5 changes: 5 additions & 0 deletions tests/topotests/bgp_nhc/r2/frr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ int r2-eth1
ip address 10.254.0.2/24
!
router bgp 65002
bgp router-id 10.255.0.2
no bgp ebgp-requires-policy
no bgp suppress-duplicates
no bgp network import-check
bgp bestpath as-path multipath-relax
neighbor 10.255.0.1 remote-as external
neighbor 10.255.0.1 timers 1 3
Expand All @@ -22,4 +24,7 @@ router bgp 65002
neighbor 10.254.0.5 remote-as external
neighbor 10.254.0.5 timers 1 3
neighbor 10.254.0.5 timers connect 1
address-family ipv4 unicast
network 10.0.0.2/32
exit-address-family
!
3 changes: 3 additions & 0 deletions tests/topotests/bgp_nhc/r3/frr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ int r3-eth0
ip address 10.254.0.3/24
!
router bgp 65003
bgp router-id 10.255.0.3
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 10.254.0.2 remote-as external
neighbor 10.254.0.2 timers 1 3
neighbor 10.254.0.2 timers connect 1
neighbor 10.254.0.2 send-nexthop-characteristics
address-family ipv4 unicast
network 10.0.0.1/32
network 10.0.0.3/32
exit-address-family
!
1 change: 1 addition & 0 deletions tests/topotests/bgp_nhc/r4/frr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ int r4-eth0
ip address 10.254.0.4/24
!
router bgp 65004
bgp router-id 10.255.0.4
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 10.254.0.2 remote-as external
Expand Down
1 change: 1 addition & 0 deletions tests/topotests/bgp_nhc/r5/frr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ int r5-eth0
ip address 10.254.0.5/24
!
router bgp 65005
bgp router-id 10.255.0.5
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 10.254.0.2 remote-as external
Expand Down
1 change: 1 addition & 0 deletions tests/topotests/bgp_nhc/r6/frr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ int r6-eth2
ip address 10.255.68.6/24
!
router bgp 65006
bgp router-id 10.255.0.6
no bgp ebgp-requires-policy
no bgp suppress-duplicates
bgp bestpath as-path multipath-relax
Expand Down
2 changes: 1 addition & 1 deletion tests/topotests/bgp_nhc/r7/frr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ int r7-eth0
ip address 10.255.67.7/24
!
router bgp 65007
bgp router-id 10.254.0.7
bgp router-id 10.255.0.7
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 10.255.67.6 remote-as external
Expand Down
2 changes: 1 addition & 1 deletion tests/topotests/bgp_nhc/r8/frr.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ int r8-eth0
ip address 10.255.68.8/24
!
router bgp 65008
bgp router-id 10.254.0.8
bgp router-id 10.255.0.8
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 10.255.68.6 remote-as external
Expand Down
Loading
Loading