diff options
Diffstat (limited to 'bgpd/bgp_label.c')
-rw-r--r-- | bgpd/bgp_label.c | 137 |
1 files changed, 129 insertions, 8 deletions
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index dcaaea686..a219c407d 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -120,20 +120,141 @@ mpls_label_t bgp_adv_label(struct bgp_node *rn, struct bgp_path_info *pi, return rn->local_label; } +/** + * This is passed as the callback function to bgp_labelpool.c:bgp_lp_get() + * by bgp_reg_dereg_for_label() when a label needs to be obtained from + * label pool. + * Note that it will reject the allocated label if a label index is found, + * because the label index supposes predictable labels + */ +int bgp_reg_for_label_callback(mpls_label_t new_label, void *labelid, + bool allocated) +{ + struct bgp_path_info *pi = (struct bgp_path_info *)labelid; + struct bgp_node *rn = (struct bgp_node *)pi->net; + char addr[PREFIX_STRLEN]; + + prefix2str(&rn->p, addr, PREFIX_STRLEN); + + if (BGP_DEBUG(labelpool, LABELPOOL)) + zlog_debug("%s: FEC %s label=%u, allocated=%d", __func__, addr, + new_label, allocated); + + if (!allocated) { + /* + * previously-allocated label is now invalid + */ + if (pi->attr->label_index == MPLS_INVALID_LABEL_INDEX + && pi->attr->label != MPLS_LABEL_NONE + && CHECK_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL)) { + bgp_unregister_for_label(rn); + label_ntop(MPLS_LABEL_IMPLICIT_NULL, 1, + &rn->local_label); + bgp_set_valid_label(&rn->local_label); + } + return 0; + } + + /* + * label index is assigned, this should be handled by SR-related code, + * so retry FEC registration and then reject label allocation for + * it to be released to label pool + */ + if (pi->attr->label_index != MPLS_INVALID_LABEL_INDEX) { + flog_err( + EC_BGP_LABEL, + "%s: FEC %s Rejecting allocated label %u as Label Index is %u", + __func__, addr, new_label, pi->attr->label_index); + + bgp_register_for_label(pi->net, pi); + + return -1; + } + + if (pi->attr->label != MPLS_INVALID_LABEL) { + if (new_label == pi->attr->label) { + /* already have same label, accept but do nothing */ + return 0; + } + /* Shouldn't happen: different label allocation */ + flog_err(EC_BGP_LABEL, + "%s: %s had label %u but got new assignment %u", + __func__, addr, pi->attr->label, new_label); + /* continue means use new one */ + } + + label_ntop(new_label, 1, &rn->local_label); + bgp_set_valid_label(&rn->local_label); + + /* + * Get back to registering the FEC + */ + bgp_register_for_label(pi->net, pi); + + return 0; +} + void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi, - int reg) + bool reg) { + bool with_label_index = false; struct stream *s; struct prefix *p; + mpls_label_t *local_label; int command; uint16_t flags = 0; size_t flags_pos = 0; + char addr[PREFIX_STRLEN]; + + p = &(rn->p); + local_label = &(rn->local_label); + /* this prevents the loop when we're called by + * bgp_reg_for_label_callback() + */ + bool have_label_to_reg = bgp_is_valid_label(local_label) + && label_pton(local_label) != MPLS_LABEL_IMPLICIT_NULL; + + if (reg) { + assert(pi); + /* + * Determine if we will let zebra should derive label from + * label index instead of bgpd requesting from label pool + */ + if (CHECK_FLAG(pi->attr->flag, + ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) + && pi->attr->label_index != BGP_INVALID_LABEL_INDEX) { + with_label_index = true; + } else { + /* + * If no label index was provided -- assume any label + * from label pool will do. This means that label index + * always takes precedence over auto-assigned labels. + */ + if (!have_label_to_reg) { + if (BGP_DEBUG(labelpool, LABELPOOL)) { + prefix2str(p, addr, PREFIX_STRLEN); + zlog_debug("%s: Requesting label from LP for %s", + __func__, addr); + } + /* bgp_reg_for_label_callback() will call back + * __func__ when it gets a label from the pool. + * This means we'll never register FECs without + * valid labels. + */ + bgp_lp_get(LP_TYPE_BGP_LU, pi, + bgp_reg_for_label_callback); + return; + } + } + } /* Check socket. */ if (!zclient || zclient->sock < 0) return; - p = &(rn->p); + /* If the route node has a local_label assigned or the + * path node has an MPLS SR label index allowing zebra to + * derive the label, proceed with registration. */ s = zclient->obuf; stream_reset(s); command = (reg) ? ZEBRA_FEC_REGISTER : ZEBRA_FEC_UNREGISTER; @@ -143,12 +264,12 @@ void bgp_reg_dereg_for_label(struct bgp_node *rn, struct bgp_path_info *pi, stream_putw(s, PREFIX_FAMILY(p)); stream_put_prefix(s, p); if (reg) { - assert(pi); - if (pi->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) { - if (pi->attr->label_index != BGP_INVALID_LABEL_INDEX) { - flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX; - stream_putl(s, pi->attr->label_index); - } + if (have_label_to_reg) { + flags |= ZEBRA_FEC_REGISTER_LABEL; + stream_putl(s, label_pton(local_label)); + } else if (with_label_index) { + flags |= ZEBRA_FEC_REGISTER_LABEL_INDEX; + stream_putl(s, pi->attr->label_index); } SET_FLAG(rn->flags, BGP_NODE_REGISTERED_FOR_LABEL); } else |