diff options
| -rw-r--r-- | bgpd/bgp_attr.c | 26 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 6 | ||||
| -rw-r--r-- | ldpd/lde.c | 230 | ||||
| -rw-r--r-- | tests/topotests/bgp_confederation_astype/__init__.py | 0 | ||||
| -rw-r--r-- | tests/topotests/bgp_confederation_astype/r1/bgpd.conf | 12 | ||||
| -rw-r--r-- | tests/topotests/bgp_confederation_astype/r1/zebra.conf | 7 | ||||
| -rw-r--r-- | tests/topotests/bgp_confederation_astype/r2/bgpd.conf | 13 | ||||
| -rw-r--r-- | tests/topotests/bgp_confederation_astype/r2/zebra.conf | 4 | ||||
| -rw-r--r-- | tests/topotests/bgp_confederation_astype/r3/bgpd.conf | 10 | ||||
| -rw-r--r-- | tests/topotests/bgp_confederation_astype/r3/zebra.conf | 4 | ||||
| -rw-r--r-- | tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py | 140 |
11 files changed, 320 insertions, 132 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index fcfb1d64e0..1e2698cd92 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1645,6 +1645,14 @@ static enum bgp_attr_parse_ret bgp_attr_aspath_check(struct peer *const peer, */ struct aspath *aspath; + /* Refresh peer's type. If we set e.g.: AS_EXTERNAL/AS_INTERNAL, + * then peer->sort remains BGP_PEER_EBGP/IBGP, hence we need to + * have an actual type before checking. + * This is especially a case for BGP confederation peers, to avoid + * receiving and treating AS_PATH as malformed. + */ + (void)peer_sort(peer); + /* Confederation sanity check. */ if ((peer->sort == BGP_PEER_CONFED && !aspath_left_confed_check(attr->aspath)) @@ -4295,8 +4303,22 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, aspath = aspath_delete_confed_seq(aspath); if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) { - /* Stuff our path CONFED_ID on the front */ - aspath = aspath_add_seq(aspath, bgp->confed_id); + /* A confed member, so we need to do the + * AS_CONFED_SEQUENCE thing if it's outside a common + * administration. + * Configured confederation peers MUST be validated + * under BGP_PEER_CONFED, but if we have configured + * remote-as as AS_EXTERNAL, we need to check again + * if the peer belongs to us. + */ + if (bgp_confederation_peers_check(bgp, peer->as)) { + aspath = aspath_dup(attr->aspath); + aspath = aspath_add_confed_seq(aspath, + peer->local_as); + } else { + /* Stuff our path CONFED_ID on the front */ + aspath = aspath_add_seq(aspath, bgp->confed_id); + } } else { if (peer->change_local_as) { /* If replace-as is specified, we only use the diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index f2250f98c3..0fd0dafa22 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -2041,9 +2041,9 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, /* If the peer is not part of our confederation, and its not an iBGP peer then spoof the source AS */ - if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION) - && !bgp_confederation_peers_check(bgp, *as) - && bgp->as != *as) + if (bgp_config_check(bgp, BGP_CONFIG_CONFEDERATION) && + !bgp_confederation_peers_check(bgp, *as) && *as && + bgp->as != *as) local_as = bgp->confed_id; else local_as = bgp->as; diff --git a/ldpd/lde.c b/ldpd/lde.c index edd13fed35..325b33d057 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -261,8 +261,7 @@ static void lde_dispatch_imsg(struct thread *thread) case IMSG_LABEL_MAPPING_FULL: ln = lde_nbr_find(imsg.hdr.peerid); if (ln == NULL) { - log_debug("%s: cannot find lde neighbor", - __func__); + log_debug("%s: cannot find lde neighbor", __func__); break; } @@ -273,15 +272,13 @@ static void lde_dispatch_imsg(struct thread *thread) case IMSG_LABEL_RELEASE: case IMSG_LABEL_WITHDRAW: case IMSG_LABEL_ABORT: - if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct map)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct map)) fatalx("lde_dispatch_imsg: wrong imsg len"); map = imsg.data; ln = lde_nbr_find(imsg.hdr.peerid); if (ln == NULL) { - log_debug("%s: cannot find lde neighbor", - __func__); + log_debug("%s: cannot find lde neighbor", __func__); break; } @@ -304,49 +301,45 @@ static void lde_dispatch_imsg(struct thread *thread) } break; case IMSG_ADDRESS_ADD: - if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct lde_addr)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct lde_addr)) fatalx("lde_dispatch_imsg: wrong imsg len"); lde_addr = imsg.data; ln = lde_nbr_find(imsg.hdr.peerid); if (ln == NULL) { - log_debug("%s: cannot find lde neighbor", - __func__); + log_debug("%s: cannot find lde neighbor", __func__); break; } + if (lde_address_add(ln, lde_addr) < 0) { log_debug("%s: cannot add address %s, it already exists", __func__, log_addr(lde_addr->af, &lde_addr->addr)); } break; case IMSG_ADDRESS_DEL: - if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct lde_addr)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct lde_addr)) fatalx("lde_dispatch_imsg: wrong imsg len"); lde_addr = imsg.data; ln = lde_nbr_find(imsg.hdr.peerid); if (ln == NULL) { - log_debug("%s: cannot find lde neighbor", - __func__); + log_debug("%s: cannot find lde neighbor", __func__); break; } + if (lde_address_del(ln, lde_addr) < 0) { log_debug("%s: cannot delete address %s, it does not exist", __func__, log_addr(lde_addr->af, &lde_addr->addr)); } break; case IMSG_NOTIFICATION: - if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct notify_msg)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct notify_msg)) fatalx("lde_dispatch_imsg: wrong imsg len"); nm = imsg.data; ln = lde_nbr_find(imsg.hdr.peerid); if (ln == NULL) { - log_debug("%s: cannot find lde neighbor", - __func__); + log_debug("%s: cannot find lde neighbor", __func__); break; } @@ -366,8 +359,7 @@ static void lde_dispatch_imsg(struct thread *thread) } break; case IMSG_NEIGHBOR_UP: - if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct lde_nbr)) + if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(struct lde_nbr)) fatalx("lde_dispatch_imsg: wrong imsg len"); if (lde_nbr_find(imsg.hdr.peerid)) @@ -386,18 +378,15 @@ static void lde_dispatch_imsg(struct thread *thread) case IMSG_CTL_SHOW_L2VPN_PW: l2vpn_pw_ctl(imsg.hdr.pid); - lde_imsg_compose_ldpe(IMSG_CTL_END, 0, - imsg.hdr.pid, NULL, 0); + lde_imsg_compose_ldpe(IMSG_CTL_END, 0, imsg.hdr.pid, NULL, 0); break; case IMSG_CTL_SHOW_L2VPN_BINDING: l2vpn_binding_ctl(imsg.hdr.pid); - lde_imsg_compose_ldpe(IMSG_CTL_END, 0, - imsg.hdr.pid, NULL, 0); + lde_imsg_compose_ldpe(IMSG_CTL_END, 0, imsg.hdr.pid, NULL, 0); break; default: - log_debug("%s: unexpected imsg %d", __func__, - imsg.hdr.type); + log_debug("%s: unexpected imsg %d", __func__, imsg.hdr.type); break; } imsg_free(&imsg); @@ -452,8 +441,7 @@ static void lde_dispatch_parent(struct thread *thread) switch (imsg.hdr.type) { case IMSG_IFSTATUS: - if (imsg.hdr.len != IMSG_HEADER_SIZE + - sizeof(struct kif)) + if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(struct kif)) fatalx("IFSTATUS imsg with wrong len"); kif = imsg.data; @@ -481,18 +469,15 @@ static void lde_dispatch_parent(struct thread *thread) } break; case IMSG_PW_UPDATE: - if (imsg.hdr.len != IMSG_HEADER_SIZE + - sizeof(struct zapi_pw_status)) + if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(struct zapi_pw_status)) fatalx("PW_UPDATE imsg with wrong len"); if (l2vpn_pw_status_update(imsg.data) != 0) - log_warnx("%s: error updating PW status", - __func__); + log_warnx("%s: error updating PW status", __func__); break; case IMSG_NETWORK_ADD: case IMSG_NETWORK_UPDATE: - if (imsg.hdr.len != IMSG_HEADER_SIZE + - sizeof(struct kroute)) { + if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(struct kroute)) { log_warnx("%s: wrong imsg len", __func__); break; } @@ -516,9 +501,8 @@ static void lde_dispatch_parent(struct thread *thread) switch (imsg.hdr.type) { case IMSG_NETWORK_ADD: lde_kernel_insert(&fec, kr->af, &kr->nexthop, - kr->ifindex, kr->route_type, - kr->route_instance, - kr->flags & F_CONNECTED, NULL); + kr->ifindex, kr->route_type, kr->route_instance, + CHECK_FLAG(kr->flags, F_CONNECTED), NULL); break; case IMSG_NETWORK_UPDATE: lde_kernel_update(&fec); @@ -556,8 +540,7 @@ static void lde_dispatch_parent(struct thread *thread) ldp_agentx_enabled(); break; case IMSG_RECONF_CONF: - if ((nconf = malloc(sizeof(struct ldpd_conf))) == - NULL) + if ((nconf = malloc(sizeof(struct ldpd_conf))) == NULL) fatal(NULL); memcpy(nconf, imsg.data, sizeof(struct ldpd_conf)); @@ -681,8 +664,7 @@ static void lde_dispatch_parent(struct thread *thread) } break; default: - log_debug("%s: unexpected imsg %d", __func__, - imsg.hdr.type); + log_debug("%s: unexpected imsg %d", __func__, imsg.hdr.type); break; } imsg_free(&imsg); @@ -708,7 +690,7 @@ static bool lde_fec_connected(const struct fec_node *fn) struct fec_nh *fnh; LIST_FOREACH(fnh, &fn->nexthops, entry) - if (fnh->flags & F_FEC_NH_CONNECTED) + if (CHECK_FLAG(fnh->flags, F_FEC_NH_CONNECTED)) return true; return false; @@ -719,7 +701,7 @@ static bool lde_fec_outside_mpls_network(const struct fec_node *fn) struct fec_nh *fnh; LIST_FOREACH(fnh, &fn->nexthops, entry) - if (!(fnh->flags & F_FEC_NH_NO_LDP)) + if (!CHECK_FLAG(fnh->flags, F_FEC_NH_NO_LDP)) return false; return true; @@ -732,18 +714,20 @@ lde_update_label(struct fec_node *fn) /* should we allocate a label for this fec? */ switch (fn->fec.type) { case FEC_TYPE_IPV4: - if ((ldeconf->ipv4.flags & F_LDPD_AF_ALLOCHOSTONLY) + if (CHECK_FLAG(ldeconf->ipv4.flags, F_LDPD_AF_ALLOCHOSTONLY) && fn->fec.u.ipv4.prefixlen != IPV4_MAX_BITLEN) return (NO_LABEL); + if (lde_acl_check(ldeconf->ipv4.acl_label_allocate_for, AF_INET, (union ldpd_addr *)&fn->fec.u.ipv4.prefix, fn->fec.u.ipv4.prefixlen) != FILTER_PERMIT) return (NO_LABEL); break; case FEC_TYPE_IPV6: - if ((ldeconf->ipv6.flags & F_LDPD_AF_ALLOCHOSTONLY) + if (CHECK_FLAG(ldeconf->ipv6.flags, F_LDPD_AF_ALLOCHOSTONLY) && fn->fec.u.ipv6.prefixlen != IPV6_MAX_BITLEN) return (NO_LABEL); + if (lde_acl_check(ldeconf->ipv6.acl_label_allocate_for, AF_INET6, (union ldpd_addr *)&fn->fec.u.ipv6.prefix, fn->fec.u.ipv6.prefixlen) != FILTER_PERMIT) @@ -764,16 +748,18 @@ lde_update_label(struct fec_node *fn) /* choose implicit or explicit-null depending on configuration */ switch (fn->fec.type) { case FEC_TYPE_IPV4: - if (!(ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL)) + if (!CHECK_FLAG(ldeconf->ipv4.flags, F_LDPD_AF_EXPNULL)) return (MPLS_LABEL_IMPLICIT_NULL); + if (lde_acl_check(ldeconf->ipv4.acl_label_expnull_for, AF_INET, (union ldpd_addr *)&fn->fec.u.ipv4.prefix, fn->fec.u.ipv4.prefixlen) != FILTER_PERMIT) return (MPLS_LABEL_IMPLICIT_NULL); return MPLS_LABEL_IPV4_EXPLICIT_NULL; case FEC_TYPE_IPV6: - if (!(ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL)) + if (!CHECK_FLAG(ldeconf->ipv6.flags, F_LDPD_AF_EXPNULL)) return (MPLS_LABEL_IMPLICIT_NULL); + if (lde_acl_check(ldeconf->ipv6.acl_label_expnull_for, AF_INET6, (union ldpd_addr *)&fn->fec.u.ipv6.prefix, fn->fec.u.ipv6.prefixlen) != FILTER_PERMIT) @@ -803,7 +789,7 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) * Ordered Control: don't program label into HW until a * labelmap msg has been received from upstream router */ - if (fnh->flags & F_FEC_NH_DEFER) + if (CHECK_FLAG(fnh->flags, F_FEC_NH_DEFER)) return; switch (fn->fec.type) { @@ -818,8 +804,7 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.remote_label = fnh->remote_label; kr.route_type = fnh->route_type; kr.route_instance = fnh->route_instance; - lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, - sizeof(kr)); + lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, sizeof(kr)); break; case FEC_TYPE_IPV6: memset(&kr, 0, sizeof(kr)); @@ -833,8 +818,7 @@ lde_send_change_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.route_type = fnh->route_type; kr.route_instance = fnh->route_instance; - lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, - sizeof(kr)); + lde_imsg_compose_parent(IMSG_KLABEL_CHANGE, 0, &kr, sizeof(kr)); break; case FEC_TYPE_PWID: pw = (struct l2vpn_pw *) fn->data; @@ -871,8 +855,7 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.route_type = fnh->route_type; kr.route_instance = fnh->route_instance; - lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, - sizeof(kr)); + lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, sizeof(kr)); break; case FEC_TYPE_IPV6: memset(&kr, 0, sizeof(kr)); @@ -886,8 +869,7 @@ lde_send_delete_klabel(struct fec_node *fn, struct fec_nh *fnh) kr.route_type = fnh->route_type; kr.route_instance = fnh->route_instance; - lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, - sizeof(kr)); + lde_imsg_compose_parent(IMSG_KLABEL_DELETE, 0, &kr, sizeof(kr)); break; case FEC_TYPE_PWID: pw = (struct l2vpn_pw *) fn->data; @@ -967,7 +949,7 @@ lde_fec2map(struct fec *fec, struct map *map) map->type = MAP_TYPE_PWID; map->fec.pwid.type = fec->u.pwid.type; map->fec.pwid.group_id = 0; - map->flags |= F_MAP_PW_ID; + SET_FLAG(map->flags, F_MAP_PW_ID); map->fec.pwid.pwid = fec->u.pwid.pwid; break; } @@ -1021,9 +1003,9 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) * a labelmap message is received from downstream router * and don't send labelmap back to downstream router */ - if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) { + if (CHECK_FLAG(ldeconf->flags, F_LDPD_ORDERED_CONTROL)) { LIST_FOREACH(fnh, &fn->nexthops, entry) { - if (fnh->flags & F_FEC_NH_DEFER) + if (CHECK_FLAG(fnh->flags, F_FEC_NH_DEFER)) continue; if (lde_address_find(ln, fnh->af, &fnh->nexthop)) @@ -1061,9 +1043,11 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) case FEC_TYPE_IPV4: if (!ln->v4_enabled) return; + if (lde_acl_check(ldeconf->ipv4.acl_label_advertise_to, AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT) return; + if (lde_acl_check(ldeconf->ipv4.acl_label_advertise_for, AF_INET, (union ldpd_addr *)&fn->fec.u.ipv4.prefix, fn->fec.u.ipv4.prefixlen) != FILTER_PERMIT) @@ -1072,9 +1056,11 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) case FEC_TYPE_IPV6: if (!ln->v6_enabled) return; + if (lde_acl_check(ldeconf->ipv6.acl_label_advertise_to, AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT) return; + if (lde_acl_check(ldeconf->ipv6.acl_label_advertise_for, AF_INET6, (union ldpd_addr *)&fn->fec.u.ipv6.prefix, fn->fec.u.ipv6.prefixlen) != FILTER_PERMIT) @@ -1086,12 +1072,14 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) /* not the remote end of the pseudowire */ return; - map.flags |= F_MAP_PW_IFMTU; + SET_FLAG(map.flags, F_MAP_PW_IFMTU); map.fec.pwid.ifmtu = pw->l2vpn->mtu; - if (pw->flags & F_PW_CWORD) - map.flags |= F_MAP_PW_CWORD; - if (pw->flags & F_PW_STATUSTLV) { - map.flags |= F_MAP_PW_STATUS; + + if (CHECK_FLAG(pw->flags, F_PW_CWORD)) + SET_FLAG(map.flags, F_MAP_PW_CWORD); + + if (CHECK_FLAG(pw->flags, F_PW_STATUSTLV)) { + SET_FLAG(map.flags, F_MAP_PW_STATUS); map.pw_status = pw->local_status; } break; @@ -1149,8 +1137,8 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, /* not the remote end of the pseudowire */ return; - if (pw->flags & F_PW_CWORD) - map.flags |= F_MAP_PW_CWORD; + if (CHECK_FLAG(pw->flags, F_PW_CWORD)) + SET_FLAG(map.flags, F_MAP_PW_CWORD); break; } map.label = fn->local_label; @@ -1161,7 +1149,7 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, map.st.status_code = st->status_code; map.st.msg_id = st->msg_id; map.st.msg_type = st->msg_type; - map.flags |= F_MAP_STATUS; + SET_FLAG(map.flags, F_MAP_STATUS); } /* SWd.1: send label withdraw. */ @@ -1184,10 +1172,10 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, if (lde_wildcard_apply(wcard, &fn->fec, me) == 0) continue; - lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, - &fn->fec); + lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); if (lw == NULL) lw = lde_wdraw_add(ln, fn); + lw->label = map.label; } } @@ -1271,8 +1259,8 @@ lde_send_labelrelease(struct lde_nbr *ln, struct fec_node *fn, /* not the remote end of the pseudowire */ return; - if (pw->flags & F_PW_CWORD) - map.flags |= F_MAP_PW_CWORD; + if (CHECK_FLAG(pw->flags, F_PW_CWORD)) + SET_FLAG(map.flags, F_MAP_PW_CWORD); break; } } else @@ -1333,8 +1321,7 @@ lde_send_labelrequest(struct lde_nbr *ln, struct fec_node *fn, lde_imsg_compose_ldpe(IMSG_REQUEST_ADD, ln->peerid, 0, &map, sizeof(map)); if (single) - lde_imsg_compose_ldpe(IMSG_REQUEST_ADD_END, - ln->peerid, 0, NULL, 0); + lde_imsg_compose_ldpe(IMSG_REQUEST_ADD_END, ln->peerid, 0, NULL, 0); /* SLRq.4: record sent request */ RB_FOREACH(f, fec_tree, &ft) { @@ -1386,7 +1373,7 @@ lde_send_notification_eol_prefix(struct lde_nbr *ln, int af) nm.fec.type = MAP_TYPE_TYPED_WCARD; nm.fec.fec.twcard.type = MAP_TYPE_PREFIX; nm.fec.fec.twcard.u.prefix_af = af; - nm.flags |= F_NOTIF_FEC; + SET_FLAG(nm.flags, F_NOTIF_FEC); lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm, sizeof(nm)); @@ -1402,7 +1389,7 @@ lde_send_notification_eol_pwid(struct lde_nbr *ln, uint16_t pw_type) nm.fec.type = MAP_TYPE_TYPED_WCARD; nm.fec.fec.twcard.type = MAP_TYPE_PWID; nm.fec.fec.twcard.u.pw_type = pw_type; - nm.flags |= F_NOTIF_FEC; + SET_FLAG(nm.flags, F_NOTIF_FEC); lde_imsg_compose_ldpe(IMSG_NOTIFICATION_SEND, ln->peerid, 0, &nm, sizeof(nm)); @@ -1465,8 +1452,7 @@ lde_nbr_del(struct lde_nbr *ln) switch (f->type) { case FEC_TYPE_IPV4: case FEC_TYPE_IPV6: - if (!lde_address_find(ln, fnh->af, - &fnh->nexthop)) + if (!lde_address_find(ln, fnh->af, &fnh->nexthop)) continue; /* @@ -1478,8 +1464,8 @@ lde_nbr_del(struct lde_nbr *ln) * to other neighbors for all fecs from neighbor * going down */ - if (ldeconf->flags & F_LDPD_ORDERED_CONTROL) { - fnh->flags |= F_FEC_NH_DEFER; + if (CHECK_FLAG(ldeconf->flags, F_LDPD_ORDERED_CONTROL)) { + SET_FLAG(fnh->flags, F_FEC_NH_DEFER); RB_FOREACH(lnbr, nbr_tree, &lde_nbrs) { if (ln->peerid == lnbr->peerid) @@ -1594,8 +1580,7 @@ lde_nbr_addr_update(struct lde_nbr *ln, struct lde_addr *lde_addr, int removed) continue; LIST_FOREACH(fnh, &fn->nexthops, entry) { - if (ldp_addrcmp(fnh->af, &fnh->nexthop, - &lde_addr->addr)) + if (ldp_addrcmp(fnh->af, &fnh->nexthop, &lde_addr->addr)) continue; if (removed) { @@ -1658,15 +1643,13 @@ lde_map_add(struct lde_nbr *ln, struct fec_node *fn, int sent) RB_INSERT(lde_map_head, &fn->upstream, me); me->head = &fn->upstream; if (fec_insert(&ln->sent_map, &me->fec)) - log_warnx("failed to add %s to sent map", - log_fec(&me->fec)); + log_warnx("failed to add %s to sent map", log_fec(&me->fec)); /* XXX on failure more cleanup is needed */ } else { RB_INSERT(lde_map_head, &fn->downstream, me); me->head = &fn->downstream; if (fec_insert(&ln->recv_map, &me->fec)) - log_warnx("failed to add %s to recv map", - log_fec(&me->fec)); + log_warnx("failed to add %s to recv map", log_fec(&me->fec)); } return (me); @@ -1703,8 +1686,7 @@ lde_map_pending_add(struct lde_nbr *ln, struct fec_node *fn) *map = fn->fec; if (fec_insert(&ln->sent_map_pending, map)) - log_warnx("failed to add %s to sent map (pending)", - log_fec(map)); + log_warnx("failed to add %s to sent map (pending)", log_fec(map)); return (map); } @@ -1762,8 +1744,7 @@ lde_wdraw_add(struct lde_nbr *ln, struct fec_node *fn) lw->fec = fn->fec; if (fec_insert(&ln->sent_wdraw, &lw->fec)) - log_warnx("failed to add %s to sent wdraw", - log_fec(&lw->fec)); + log_warnx("failed to add %s to sent wdraw", log_fec(&lw->fec)); return (lw); } @@ -1786,13 +1767,9 @@ lde_change_egress_label(int af) RB_FOREACH(ln, nbr_tree, &lde_nbrs) { lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IMPLICIT_NULL); if (ln->v4_enabled) - lde_send_labelwithdraw_wcard( - ln, - MPLS_LABEL_IPV4_EXPLICIT_NULL); + lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV4_EXPLICIT_NULL); if (ln->v6_enabled) - lde_send_labelwithdraw_wcard( - ln, - MPLS_LABEL_IPV6_EXPLICIT_NULL); + lde_send_labelwithdraw_wcard(ln, MPLS_LABEL_IPV6_EXPLICIT_NULL); } /* update label of connected routes */ @@ -1820,8 +1797,7 @@ lde_change_egress_label(int af) lde_send_labelmapping(ln, fn, 0); } RB_FOREACH(ln, nbr_tree, &lde_nbrs) - lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, - NULL, 0); + lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0); } void @@ -1861,8 +1837,7 @@ lde_change_allocate_filter(int af) if (fn->local_label != new_label) { if (new_label == NO_LABEL) RB_FOREACH(ln, nbr_tree, &lde_nbrs) - lde_send_labelwithdraw(ln, fn, - NULL, NULL); + lde_send_labelwithdraw(ln, fn, NULL, NULL); fn->local_label = new_label; if (fn->local_label != NO_LABEL) @@ -1870,6 +1845,7 @@ lde_change_allocate_filter(int af) lde_send_labelmapping(ln, fn, 0); } } + RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0); @@ -1915,34 +1891,30 @@ lde_change_advertise_filter(int af) case AF_INET: if (fn->fec.type != FEC_TYPE_IPV4) continue; - prefix = (union ldpd_addr *) - &fn->fec.u.ipv4.prefix; + prefix = (union ldpd_addr *)&fn->fec.u.ipv4.prefix; plen = fn->fec.u.ipv4.prefixlen; break; case FEC_TYPE_IPV6: if (fn->fec.type != FEC_TYPE_IPV6) continue; - prefix = (union ldpd_addr *) - &fn->fec.u.ipv6.prefix; + prefix = (union ldpd_addr *)&fn->fec.u.ipv6.prefix; plen = fn->fec.u.ipv6.prefixlen; break; default: continue; } + if (lde_acl_check(acl_for_filter, af, prefix, plen) != FILTER_PERMIT) { - me = (struct lde_map *)fec_find( - &ln->sent_map, &fn->fec); + me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); if (me) /* fec filtered withdraw */ - lde_send_labelwithdraw(ln, fn, - NULL, NULL); + lde_send_labelwithdraw(ln, fn, NULL, NULL); } else /* fec allowed send map */ lde_send_labelmapping(ln, fn, 0); } - lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, - ln->peerid, 0, NULL, 0); + lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0); } } } @@ -1988,13 +1960,12 @@ lde_change_accept_filter(int af) RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; if (fn->fec.type == type) { - me = (struct lde_map *)fec_find( - &ln->recv_map, &fn->fec); + me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); if (me) lde_map_del(ln, me, 0); } } - } else if (ln->flags & F_NBR_CAP_TWCARD) { + } else if (CHECK_FLAG(ln->flags, F_NBR_CAP_TWCARD)) { /* This neighbor is allowed and supports type * wildcard so send a labelrequest * to get any new labels from neighbor @@ -2007,15 +1978,13 @@ lde_change_accept_filter(int af) case AF_INET: if (fn->fec.type != FEC_TYPE_IPV4) continue; - prefix = (union ldpd_addr *) - &fn->fec.u.ipv4.prefix; + prefix = (union ldpd_addr *)&fn->fec.u.ipv4.prefix; plen = fn->fec.u.ipv4.prefixlen; break; case AF_INET6: if (fn->fec.type != FEC_TYPE_IPV6) continue; - prefix = (union ldpd_addr *) - &fn->fec.u.ipv6.prefix; + prefix = (union ldpd_addr *)&fn->fec.u.ipv6.prefix; plen = fn->fec.u.ipv6.prefixlen; break; default: @@ -2023,8 +1992,7 @@ lde_change_accept_filter(int af) } if (lde_acl_check(acl_for_filter, af, prefix, plen) != FILTER_PERMIT) { - me = (struct lde_map *)fec_find( - &ln->recv_map, &fn->fec); + me = (struct lde_map *)fec_find(&ln->recv_map, &fn->fec); if (me) lde_map_del(ln, me, 0); } @@ -2032,8 +2000,7 @@ lde_change_accept_filter(int af) lde_send_labelrequest_wcard(ln, af); } else /* Type Wildcard is not supported so restart session */ - lde_imsg_compose_ldpe(IMSG_NBR_SHUTDOWN, ln->peerid, 0, - NULL, 0); + lde_imsg_compose_ldpe(IMSG_NBR_SHUTDOWN, ln->peerid, 0, NULL, 0); } } @@ -2299,7 +2266,7 @@ lde_free_label(uint32_t label) for (ALL_LIST_ELEMENTS_RO(label_chunk_list, node, label_chunk)) { if (label <= label_chunk->end && label >= label_chunk->start) { pos = 1ULL << (label - label_chunk->start); - label_chunk->used_mask &= ~pos; + UNSET_FLAG(label_chunk->used_mask, pos); /* if nobody is using this chunk and it's not current_label_chunk, then free it */ if (!label_chunk->used_mask && (current_label_chunk != node)) { if (lde_release_label_chunk(label_chunk->start, label_chunk->end) != 0) @@ -2312,6 +2279,7 @@ lde_free_label(uint32_t label) break; } } + return; } @@ -2332,7 +2300,7 @@ lde_get_next_label(void) size = label_chunk->end - label_chunk->start + 1; for (i = 0, pos = 1; i < size; i++, pos <<= 1) { if (!(pos & label_chunk->used_mask)) { - label_chunk->used_mask |= pos; + SET_FLAG(label_chunk->used_mask, pos); label = label_chunk->start + i; goto end; } @@ -2360,12 +2328,15 @@ lde_check_filter_af(int af, struct ldpd_af_conf *af_conf, { if (strcmp(af_conf->acl_label_allocate_for, filter_name) == 0) lde_change_allocate_filter(af); + if ((strcmp(af_conf->acl_label_advertise_to, filter_name) == 0) || (strcmp(af_conf->acl_label_advertise_for, filter_name) == 0)) lde_change_advertise_filter(af); + if ((strcmp(af_conf->acl_label_accept_for, filter_name) == 0) || (strcmp(af_conf->acl_label_accept_from, filter_name) == 0)) lde_change_accept_filter(af); + if (strcmp(af_conf->acl_label_expnull_for, filter_name) == 0) lde_change_expnull_for_filter(af); } @@ -2379,6 +2350,7 @@ void lde_route_update(struct iface *iface, int af) /* update label of non-connected routes */ log_debug("update labels for interface %s", iface->name); + RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; if (IS_MPLS_UNRESERVED_LABEL(fn->local_label)) @@ -2405,13 +2377,13 @@ void lde_route_update(struct iface *iface, int af) * may need new label. If no LDP configured * treat fec as a connected route */ - if (fnh->flags & F_FEC_NH_CONNECTED) + if (CHECK_FLAG(fnh->flags, F_FEC_NH_CONNECTED)) break; if (fnh->ifindex != iface->ifindex) continue; - fnh->flags &= ~F_FEC_NH_NO_LDP; + UNSET_FLAG(fnh->flags, F_FEC_NH_NO_LDP); if (IS_MPLS_RESERVED_LABEL(fn->local_label)) { fn->local_label = NO_LABEL; fn->local_label = lde_update_label(fn); @@ -2423,6 +2395,7 @@ void lde_route_update(struct iface *iface, int af) break; } } + RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0); @@ -2438,6 +2411,7 @@ void lde_route_update_release(struct iface *iface, int af) /* update label of interfaces no longer running LDP */ log_debug("release all labels for interface %s af %s", iface->name, af == AF_INET ? "ipv4" : "ipv6"); + RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; @@ -2463,13 +2437,13 @@ void lde_route_update_release(struct iface *iface, int af) * removed from interface may need new label * and would be treated as a connected route */ - if (fnh->flags & F_FEC_NH_CONNECTED) + if (CHECK_FLAG(fnh->flags, F_FEC_NH_CONNECTED)) break; if (fnh->ifindex != iface->ifindex) continue; - fnh->flags |= F_FEC_NH_NO_LDP; + SET_FLAG(fnh->flags, F_FEC_NH_NO_LDP); RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_send_labelwithdraw(ln, fn, NULL, NULL); lde_free_label(fn->local_label); @@ -2481,6 +2455,7 @@ void lde_route_update_release(struct iface *iface, int af) break; } } + RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0); @@ -2498,6 +2473,7 @@ void lde_route_update_release_all(int af) */ log_debug("release all labels for address family %s", af == AF_INET ? "ipv4" : "ipv6"); + RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; switch (af) { @@ -2517,7 +2493,7 @@ void lde_route_update_release_all(int af) lde_send_labelwithdraw(ln, fn, NULL, NULL); LIST_FOREACH(fnh, &fn->nexthops, entry) { - fnh->flags |= F_FEC_NH_NO_LDP; + SET_FLAG(fnh->flags, F_FEC_NH_NO_LDP); lde_send_delete_klabel(fn, fnh); } } diff --git a/tests/topotests/bgp_confederation_astype/__init__.py b/tests/topotests/bgp_confederation_astype/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_confederation_astype/__init__.py diff --git a/tests/topotests/bgp_confederation_astype/r1/bgpd.conf b/tests/topotests/bgp_confederation_astype/r1/bgpd.conf new file mode 100644 index 0000000000..1859a1b942 --- /dev/null +++ b/tests/topotests/bgp_confederation_astype/r1/bgpd.conf @@ -0,0 +1,12 @@ +router bgp 65001 + no bgp ebgp-requires-policy + bgp confederation identifier 65300 + bgp confederation peers 65002 65003 + neighbor fabric peer-group + neighbor fabric remote-as external + neighbor 192.168.1.2 peer-group fabric + neighbor 192.168.2.2 remote-as external + address-family ipv4 unicast + neighbor fabric activate + exit-address-family +! diff --git a/tests/topotests/bgp_confederation_astype/r1/zebra.conf b/tests/topotests/bgp_confederation_astype/r1/zebra.conf new file mode 100644 index 0000000000..608a2411a3 --- /dev/null +++ b/tests/topotests/bgp_confederation_astype/r1/zebra.conf @@ -0,0 +1,7 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +int r1-eth1 + ip address 192.168.2.1/24 +! diff --git a/tests/topotests/bgp_confederation_astype/r2/bgpd.conf b/tests/topotests/bgp_confederation_astype/r2/bgpd.conf new file mode 100644 index 0000000000..697af9743c --- /dev/null +++ b/tests/topotests/bgp_confederation_astype/r2/bgpd.conf @@ -0,0 +1,13 @@ +router bgp 65002 + no bgp ebgp-requires-policy + no bgp network import-check + bgp confederation identifier 65300 + bgp confederation peers 65001 + neighbor fabric peer-group + neighbor fabric remote-as external + neighbor 192.168.1.1 peer-group fabric + address-family ipv4 unicast + network 172.16.255.254/32 + neighbor fabric activate + exit-address-family +! diff --git a/tests/topotests/bgp_confederation_astype/r2/zebra.conf b/tests/topotests/bgp_confederation_astype/r2/zebra.conf new file mode 100644 index 0000000000..cffe827363 --- /dev/null +++ b/tests/topotests/bgp_confederation_astype/r2/zebra.conf @@ -0,0 +1,4 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! diff --git a/tests/topotests/bgp_confederation_astype/r3/bgpd.conf b/tests/topotests/bgp_confederation_astype/r3/bgpd.conf new file mode 100644 index 0000000000..c1f93f66e9 --- /dev/null +++ b/tests/topotests/bgp_confederation_astype/r3/bgpd.conf @@ -0,0 +1,10 @@ +router bgp 65003 + no bgp ebgp-requires-policy + no bgp network import-check + bgp confederation identifier 65300 + bgp confederation peers 65001 + neighbor 192.168.2.1 remote-as external + address-family ipv4 unicast + network 172.16.255.254/32 + exit-address-family +! diff --git a/tests/topotests/bgp_confederation_astype/r3/zebra.conf b/tests/topotests/bgp_confederation_astype/r3/zebra.conf new file mode 100644 index 0000000000..e5a37c98ca --- /dev/null +++ b/tests/topotests/bgp_confederation_astype/r3/zebra.conf @@ -0,0 +1,4 @@ +! +int r3-eth0 + ip address 192.168.2.2/24 +! diff --git a/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py new file mode 100644 index 0000000000..5310d3b595 --- /dev/null +++ b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2022 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +""" +Test if BGP confederation works properly when using +remote-as internal/external. + +Also, check if the same works with peer-groups as well. +""" + +import os +import sys +import json +import pytest +import functools + +pytestmark = pytest.mark.bgpd + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2"), "s2": ("r1", "r3")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_confederation_astype(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp summary json")) + expected = { + "ipv4Unicast": { + "peerCount": 2, + "peers": { + "192.168.1.2": { + "hostname": "r2", + "remoteAs": 65002, + "localAs": 65001, + "pfxRcd": 1, + "state": "Established", + }, + "192.168.2.2": { + "hostname": "r3", + "remoteAs": 65003, + "localAs": 65001, + "pfxRcd": 1, + "state": "Established", + }, + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't converge" + + def _bgp_check_neighbors(): + output = json.loads(r1.vtysh_cmd("show bgp neighbors json")) + expected = { + "192.168.1.2": { + "nbrCommonAdmin": True, + "nbrConfedExternalLink": True, + "hostname": "r2", + }, + "192.168.2.2": { + "nbrCommonAdmin": True, + "nbrConfedExternalLink": True, + "hostname": "r3", + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_neighbors) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't see neighbors to be in BGP confederation" + + def _bgp_check_routes(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "172.16.255.254/32": [ + { + "valid": True, + "pathFrom": "external", + "path": "(65003)", + }, + { + "valid": True, + "pathFrom": "external", + "path": "(65002)", + }, + ] + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_check_routes) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't see routes to be in BGP confederation" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) |
