isisd: add ASLA support

Add the support of ASLA with the following TLV:

- Extended IS Reachability (already defined TLV 22)
        - Application-Specific Link Attributes (Sub-TLV 16)
          (to enable the Flex-Algo flag on a link)
                - Admin-group (Sub-Sub-TLV 3)
                - Extended Admin-group (Sub-Sub-TLV 14)

Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
This commit is contained in:
Louis Scalbert 2022-12-12 16:00:58 +01:00
parent f46e34f838
commit 5749ac83a8
3 changed files with 744 additions and 1 deletions

View file

@ -164,6 +164,154 @@ void isis_mpls_te_term(struct isis_area *area)
XFREE(MTYPE_ISIS_MPLS_TE, area->mta);
}
static void isis_link_params_update_asla(struct isis_circuit *circuit,
struct interface *ifp)
{
struct isis_asla_subtlvs *asla;
struct listnode *node, *nnode;
struct isis_ext_subtlvs *ext = circuit->ext;
int i;
if (!HAS_LINK_PARAMS(ifp)) {
list_delete_all_node(ext->aslas);
return;
}
#ifndef FABRICD
/* RFC 8919 Application Specific Link-Attributes
* is required by flex-algo application ISIS_SABM_FLAG_X
*/
if (list_isempty(circuit->area->flex_algos->flex_algos))
isis_tlvs_free_asla(ext, ISIS_SABM_FLAG_X);
else
isis_tlvs_find_alloc_asla(ext, ISIS_SABM_FLAG_X);
#endif /* ifndef FABRICD */
if (list_isempty(ext->aslas))
return;
for (ALL_LIST_ELEMENTS(ext->aslas, node, nnode, asla)) {
asla->legacy = circuit->area->asla_legacy_flag;
RESET_SUBTLV(asla);
if (asla->legacy)
continue;
/* Fulfill ASLA subTLVs from interface link parameters */
if (IS_PARAM_SET(ifp->link_params, LP_ADM_GRP)) {
asla->admin_group = ifp->link_params->admin_grp;
SET_SUBTLV(asla, EXT_ADM_GRP);
} else
UNSET_SUBTLV(asla, EXT_ADM_GRP);
if (IS_PARAM_SET(ifp->link_params, LP_EXTEND_ADM_GRP)) {
admin_group_copy(&asla->ext_admin_group,
&ifp->link_params->ext_admin_grp);
SET_SUBTLV(asla, EXT_EXTEND_ADM_GRP);
} else
UNSET_SUBTLV(asla, EXT_EXTEND_ADM_GRP);
/* Send admin-group zero for better compatibility
* https://www.rfc-editor.org/rfc/rfc7308#section-2.3.2
*/
if (circuit->area->admin_group_send_zero &&
!IS_SUBTLV(asla, EXT_ADM_GRP) &&
!IS_SUBTLV(asla, EXT_EXTEND_ADM_GRP)) {
asla->admin_group = 0;
SET_SUBTLV(asla, EXT_ADM_GRP);
admin_group_clear(&asla->ext_admin_group);
admin_group_allow_explicit_zero(&asla->ext_admin_group);
SET_SUBTLV(asla, EXT_EXTEND_ADM_GRP);
}
if (IS_PARAM_SET(ifp->link_params, LP_TE_METRIC)) {
asla->te_metric = ifp->link_params->te_metric;
SET_SUBTLV(asla, EXT_TE_METRIC);
} else
UNSET_SUBTLV(asla, EXT_TE_METRIC);
if (IS_PARAM_SET(ifp->link_params, LP_DELAY)) {
asla->delay = ifp->link_params->av_delay;
SET_SUBTLV(asla, EXT_DELAY);
} else
UNSET_SUBTLV(asla, EXT_DELAY);
if (IS_PARAM_SET(ifp->link_params, LP_MM_DELAY)) {
asla->min_delay = ifp->link_params->min_delay;
asla->max_delay = ifp->link_params->max_delay;
SET_SUBTLV(asla, EXT_MM_DELAY);
} else {
UNSET_SUBTLV(asla, EXT_MM_DELAY);
}
if (asla->standard_apps == ISIS_SABM_FLAG_X)
/* Flex-Algo ASLA does not need the following TE
* sub-TLVs
*/
continue;
if (IS_PARAM_SET(ifp->link_params, LP_MAX_BW)) {
asla->max_bw = ifp->link_params->max_bw;
SET_SUBTLV(asla, EXT_MAX_BW);
} else
UNSET_SUBTLV(asla, EXT_MAX_BW);
if (IS_PARAM_SET(ifp->link_params, LP_MAX_RSV_BW)) {
asla->max_rsv_bw = ifp->link_params->max_rsv_bw;
SET_SUBTLV(asla, EXT_MAX_RSV_BW);
} else
UNSET_SUBTLV(asla, EXT_MAX_RSV_BW);
if (IS_PARAM_SET(ifp->link_params, LP_UNRSV_BW)) {
for (i = 0; i < MAX_CLASS_TYPE; i++)
asla->unrsv_bw[i] =
ifp->link_params->unrsv_bw[i];
SET_SUBTLV(asla, EXT_UNRSV_BW);
} else
UNSET_SUBTLV(asla, EXT_UNRSV_BW);
if (IS_PARAM_SET(ifp->link_params, LP_DELAY_VAR)) {
asla->delay_var = ifp->link_params->delay_var;
SET_SUBTLV(asla, EXT_DELAY_VAR);
} else
UNSET_SUBTLV(asla, EXT_DELAY_VAR);
if (IS_PARAM_SET(ifp->link_params, LP_PKT_LOSS)) {
asla->pkt_loss = ifp->link_params->pkt_loss;
SET_SUBTLV(asla, EXT_PKT_LOSS);
} else
UNSET_SUBTLV(asla, EXT_PKT_LOSS);
if (IS_PARAM_SET(ifp->link_params, LP_RES_BW)) {
asla->res_bw = ifp->link_params->res_bw;
SET_SUBTLV(asla, EXT_RES_BW);
} else
UNSET_SUBTLV(asla, EXT_RES_BW);
if (IS_PARAM_SET(ifp->link_params, LP_AVA_BW)) {
asla->ava_bw = ifp->link_params->ava_bw;
SET_SUBTLV(asla, EXT_AVA_BW);
} else
UNSET_SUBTLV(asla, EXT_AVA_BW);
if (IS_PARAM_SET(ifp->link_params, LP_USE_BW)) {
asla->use_bw = ifp->link_params->use_bw;
SET_SUBTLV(asla, EXT_USE_BW);
} else
UNSET_SUBTLV(asla, EXT_USE_BW);
}
for (ALL_LIST_ELEMENTS(ext->aslas, node, nnode, asla)) {
if (!asla->legacy && NO_SUBTLV(asla) &&
admin_group_nb_words(&asla->ext_admin_group) == 0)
/* remove ASLA without info from the list of ASLAs to
* not send void ASLA
*/
isis_tlvs_del_asla_flex_algo(ext, asla);
}
}
/* Main initialization / update function of the MPLS TE Circuit context */
/* Call when interface TE Link parameters are modified */
void isis_link_params_update(struct isis_circuit *circuit,
@ -210,6 +358,19 @@ void isis_link_params_update(struct isis_circuit *circuit,
} else
UNSET_SUBTLV(ext, EXT_EXTEND_ADM_GRP);
/* Send admin-group zero for better compatibility
* https://www.rfc-editor.org/rfc/rfc7308#section-2.3.2
*/
if (circuit->area->admin_group_send_zero &&
!IS_SUBTLV(ext, EXT_ADM_GRP) &&
!IS_SUBTLV(ext, EXT_EXTEND_ADM_GRP)) {
ext->adm_group = 0;
SET_SUBTLV(ext, EXT_ADM_GRP);
admin_group_clear(&ext->ext_admin_group);
admin_group_allow_explicit_zero(&ext->ext_admin_group);
SET_SUBTLV(ext, EXT_EXTEND_ADM_GRP);
}
/* If known, register local IPv4 addr from ip_addr list */
if (listcount(circuit->ip_addrs) != 0) {
addr = (struct prefix_ipv4 *)listgetdata(
@ -331,6 +492,8 @@ void isis_link_params_update(struct isis_circuit *circuit,
ext->status = 0;
}
isis_link_params_update_asla(circuit, ifp);
return;
}
@ -503,7 +666,12 @@ int isis_mpls_te_update(struct interface *ifp)
isis_link_params_update(circuit, ifp);
/* ... and LSP */
if (circuit->area && IS_MPLS_TE(circuit->area->mta))
if (circuit->area &&
(IS_MPLS_TE(circuit->area->mta)
#ifndef FABRICD
|| !list_isempty(circuit->area->flex_algos->flex_algos)
#endif /* ifndef FABRICD */
))
lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
rc = 0;

View file

@ -123,6 +123,7 @@ struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void)
ext = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_ext_subtlvs));
init_item_list(&ext->adj_sid);
init_item_list(&ext->lan_sid);
ext->aslas = list_new();
admin_group_init(&ext->ext_admin_group);
@ -132,6 +133,8 @@ struct isis_ext_subtlvs *isis_alloc_ext_subtlvs(void)
void isis_del_ext_subtlvs(struct isis_ext_subtlvs *ext)
{
struct isis_item *item, *next_item;
struct listnode *node, *nnode;
struct isis_asla_subtlvs *asla;
if (!ext)
return;
@ -146,6 +149,11 @@ void isis_del_ext_subtlvs(struct isis_ext_subtlvs *ext)
XFREE(MTYPE_ISIS_SUBTLV, item);
}
for (ALL_LIST_ELEMENTS(ext->aslas, node, nnode, asla))
isis_tlvs_del_asla_flex_algo(ext, asla);
list_delete(&ext->aslas);
admin_group_term(&ext->ext_admin_group);
XFREE(MTYPE_ISIS_SUBTLV, ext);
@ -162,6 +170,8 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid)
struct isis_ext_subtlvs *rv = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*rv));
struct isis_adj_sid *adj;
struct isis_lan_adj_sid *lan;
struct listnode *node, *nnode;
struct isis_asla_subtlvs *new_asla, *asla;
/* Copy the Extended IS main part */
memcpy(rv, exts, sizeof(struct isis_ext_subtlvs));
@ -226,12 +236,133 @@ copy_item_ext_subtlvs(struct isis_ext_subtlvs *exts, uint16_t mtid)
SET_SUBTLV(rv, EXT_LAN_ADJ_SID);
}
rv->aslas = list_new();
for (ALL_LIST_ELEMENTS(exts->aslas, node, nnode, asla)) {
new_asla = XCALLOC(MTYPE_ISIS_SUBTLV,
sizeof(struct isis_asla_subtlvs));
memcpy(new_asla, asla, sizeof(struct isis_asla_subtlvs));
new_asla->ext_admin_group.bitmap.data = NULL;
admin_group_copy(&new_asla->ext_admin_group,
&asla->ext_admin_group);
listnode_add(rv->aslas, new_asla);
}
rv->ext_admin_group.bitmap.data = NULL;
admin_group_copy(&rv->ext_admin_group, &exts->ext_admin_group);
return rv;
}
static void format_item_asla_subtlvs(struct isis_asla_subtlvs *asla,
struct sbuf *buf, int indent)
{
char admin_group_buf[ADMIN_GROUP_PRINT_MAX_SIZE];
sbuf_push(buf, indent, "Application Specific Link Attributes:\n");
sbuf_push(buf, indent + 2,
"L flag: %u, SA-Length: %u, UDA-Length: %u\n", asla->legacy,
asla->standard_apps_length, asla->user_def_apps_length);
sbuf_push(buf, indent + 2, "Standard Applications: 0x%02x",
asla->standard_apps);
if (asla->standard_apps) {
uint8_t bit = asla->standard_apps;
if (bit & ISIS_SABM_FLAG_R)
sbuf_push(buf, 0, " RSVP-TE");
if (bit & ISIS_SABM_FLAG_S)
sbuf_push(buf, 0, " SR-Policy");
if (bit & ISIS_SABM_FLAG_L)
sbuf_push(buf, 0, " Loop-Free-Alternate");
if (bit & ISIS_SABM_FLAG_X)
sbuf_push(buf, 0, " Flex-Algo");
}
sbuf_push(buf, 0, "\n");
sbuf_push(buf, indent + 2, "User Defined Applications: 0x%02x\n",
asla->user_def_apps);
if (IS_SUBTLV(asla, EXT_ADM_GRP)) {
sbuf_push(buf, indent + 2, "Admin Group: 0x%08x\n",
asla->admin_group);
sbuf_push(buf, indent + 4, "Bit positions: %s\n",
admin_group_standard_print(
admin_group_buf,
indent + 2 + strlen("Admin Group: "),
asla->admin_group));
}
if (IS_SUBTLV(asla, EXT_EXTEND_ADM_GRP) &&
admin_group_nb_words(&asla->ext_admin_group) != 0) {
sbuf_push(buf, indent + 2, "Ext Admin Group: %s\n",
admin_group_string(
admin_group_buf, ADMIN_GROUP_PRINT_MAX_SIZE,
indent + 2 + strlen("Ext Admin Group: "),
&asla->ext_admin_group));
admin_group_print(admin_group_buf,
indent + 2 + strlen("Ext Admin Group: "),
&asla->ext_admin_group);
if (admin_group_buf[0] != '\0' &&
(buf->pos + strlen(admin_group_buf) +
SBUF_DEFAULT_SIZE / 2) < buf->size)
sbuf_push(buf, indent + 4, "Bit positions: %s\n",
admin_group_buf);
}
if (IS_SUBTLV(asla, EXT_MAX_BW))
sbuf_push(buf, indent + 2,
"Maximum Bandwidth: %g (Bytes/sec)\n", asla->max_bw);
if (IS_SUBTLV(asla, EXT_MAX_RSV_BW))
sbuf_push(buf, indent + 2,
"Maximum Reservable Bandwidth: %g (Bytes/sec)\n",
asla->max_rsv_bw);
if (IS_SUBTLV(asla, EXT_UNRSV_BW)) {
sbuf_push(buf, indent + 2, "Unreserved Bandwidth:\n");
for (int j = 0; j < MAX_CLASS_TYPE; j += 2) {
sbuf_push(
buf, indent + 2,
"[%d]: %g (Bytes/sec),\t[%d]: %g (Bytes/sec)\n",
j, asla->unrsv_bw[j], j + 1,
asla->unrsv_bw[j + 1]);
}
}
if (IS_SUBTLV(asla, EXT_TE_METRIC))
sbuf_push(buf, indent + 2, "Traffic Engineering Metric: %u\n",
asla->te_metric);
/* Extended metrics */
if (IS_SUBTLV(asla, EXT_DELAY))
sbuf_push(buf, indent + 2,
"%s Average Link Delay: %u (micro-sec)\n",
IS_ANORMAL(asla->delay) ? "Anomalous" : "Normal",
asla->delay);
if (IS_SUBTLV(asla, EXT_MM_DELAY)) {
sbuf_push(buf, indent + 2,
"%s Min/Max Link Delay: %u / %u (micro-sec)\n",
IS_ANORMAL(asla->min_delay) ? "Anomalous" : "Normal",
asla->min_delay & TE_EXT_MASK,
asla->max_delay & TE_EXT_MASK);
}
if (IS_SUBTLV(asla, EXT_DELAY_VAR)) {
sbuf_push(buf, indent + 2, "Delay Variation: %u (micro-sec)\n",
asla->delay_var & TE_EXT_MASK);
}
if (IS_SUBTLV(asla, EXT_PKT_LOSS))
sbuf_push(buf, indent + 2, "%s Link Packet Loss: %g (%%)\n",
IS_ANORMAL(asla->pkt_loss) ? "Anomalous" : "Normal",
(float)((asla->pkt_loss & TE_EXT_MASK) *
LOSS_PRECISION));
if (IS_SUBTLV(asla, EXT_RES_BW))
sbuf_push(buf, indent + 2,
"Unidir. Residual Bandwidth: %g (Bytes/sec)\n",
asla->res_bw);
if (IS_SUBTLV(asla, EXT_AVA_BW))
sbuf_push(buf, indent + 2,
"Unidir. Available Bandwidth: %g (Bytes/sec)\n",
asla->ava_bw);
if (IS_SUBTLV(asla, EXT_USE_BW))
sbuf_push(buf, indent + 2,
"Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
asla->use_bw);
}
/* mtid parameter is used to manage multi-topology i.e. IPv4 / IPv6 */
static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
struct sbuf *buf, struct json_object *json,
@ -240,6 +371,8 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
char admin_group_buf[ADMIN_GROUP_PRINT_MAX_SIZE];
char aux_buf[255];
char cnt_buf[255];
struct isis_asla_subtlvs *asla;
struct listnode *node;
/* Standard metrics */
if (IS_SUBTLV(exts, EXT_ADM_GRP)) {
@ -688,6 +821,8 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
lan->neighbor_id);
}
}
for (ALL_LIST_ELEMENTS_RO(exts->aslas, node, asla))
format_item_asla_subtlvs(asla, buf, indent);
}
static void free_item_ext_subtlvs(struct isis_ext_subtlvs *exts)
@ -695,10 +830,124 @@ static void free_item_ext_subtlvs(struct isis_ext_subtlvs *exts)
isis_del_ext_subtlvs(exts);
}
static int pack_item_ext_subtlv_asla(struct isis_asla_subtlvs *asla,
struct stream *s, size_t *min_len)
{
size_t subtlv_len;
size_t subtlv_len_pos;
/* Sub TLV header */
stream_putc(s, ISIS_SUBTLV_ASLA);
subtlv_len_pos = stream_get_endp(s);
stream_putc(s, 0); /* length will be filled later */
/* SABM Flag/Length */
if (asla->legacy)
stream_putc(s, ASLA_LEGACY_FLAG | asla->standard_apps_length);
else
stream_putc(s, asla->standard_apps_length);
stream_putc(s, asla->user_def_apps_length); /* UDABM Flag/Length */
stream_putc(s, asla->standard_apps);
stream_putc(s, asla->user_def_apps);
/* Administrative Group */
if (IS_SUBTLV(asla, EXT_ADM_GRP)) {
stream_putc(s, ISIS_SUBTLV_ADMIN_GRP);
stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
stream_putl(s, asla->admin_group);
}
/* Extended Administrative Group */
if (IS_SUBTLV(asla, EXT_EXTEND_ADM_GRP) &&
admin_group_nb_words(&asla->ext_admin_group) != 0) {
size_t ag_length;
size_t ag_length_pos;
struct admin_group *ag;
stream_putc(s, ISIS_SUBTLV_EXT_ADMIN_GRP);
ag_length_pos = stream_get_endp(s);
stream_putc(s, 0); /* length will be filled later*/
ag = &asla->ext_admin_group;
for (size_t i = 0; i < admin_group_nb_words(ag); i++)
stream_putl(s, ag->bitmap.data[i]);
ag_length = stream_get_endp(s) - ag_length_pos - 1;
stream_putc_at(s, ag_length_pos, ag_length);
}
if (IS_SUBTLV(asla, EXT_MAX_BW)) {
stream_putc(s, ISIS_SUBTLV_MAX_BW);
stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
stream_putf(s, asla->max_bw);
}
if (IS_SUBTLV(asla, EXT_MAX_RSV_BW)) {
stream_putc(s, ISIS_SUBTLV_MAX_RSV_BW);
stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
stream_putf(s, asla->max_rsv_bw);
}
if (IS_SUBTLV(asla, EXT_UNRSV_BW)) {
stream_putc(s, ISIS_SUBTLV_UNRSV_BW);
stream_putc(s, ISIS_SUBTLV_UNRSV_BW_SIZE);
for (int j = 0; j < MAX_CLASS_TYPE; j++)
stream_putf(s, asla->unrsv_bw[j]);
}
if (IS_SUBTLV(asla, EXT_TE_METRIC)) {
stream_putc(s, ISIS_SUBTLV_TE_METRIC);
stream_putc(s, ISIS_SUBTLV_TE_METRIC_SIZE);
stream_put3(s, asla->te_metric);
}
if (IS_SUBTLV(asla, EXT_DELAY)) {
stream_putc(s, ISIS_SUBTLV_AV_DELAY);
stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
stream_putl(s, asla->delay);
}
if (IS_SUBTLV(asla, EXT_MM_DELAY)) {
stream_putc(s, ISIS_SUBTLV_MM_DELAY);
stream_putc(s, ISIS_SUBTLV_MM_DELAY_SIZE);
stream_putl(s, asla->min_delay);
stream_putl(s, asla->max_delay);
}
if (IS_SUBTLV(asla, EXT_DELAY_VAR)) {
stream_putc(s, ISIS_SUBTLV_DELAY_VAR);
stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
stream_putl(s, asla->delay_var);
}
if (IS_SUBTLV(asla, EXT_PKT_LOSS)) {
stream_putc(s, ISIS_SUBTLV_PKT_LOSS);
stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
stream_putl(s, asla->pkt_loss);
}
if (IS_SUBTLV(asla, EXT_RES_BW)) {
stream_putc(s, ISIS_SUBTLV_RES_BW);
stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
stream_putf(s, asla->res_bw);
}
if (IS_SUBTLV(asla, EXT_AVA_BW)) {
stream_putc(s, ISIS_SUBTLV_AVA_BW);
stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
stream_putf(s, asla->ava_bw);
}
if (IS_SUBTLV(asla, EXT_USE_BW)) {
stream_putc(s, ISIS_SUBTLV_USE_BW);
stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
stream_putf(s, asla->use_bw);
}
subtlv_len = stream_get_endp(s) - subtlv_len_pos - 1;
stream_putc_at(s, subtlv_len_pos, subtlv_len);
return 0;
}
static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
struct stream *s, size_t *min_len)
{
struct isis_asla_subtlvs *asla;
struct listnode *node;
uint8_t size;
int ret;
if (STREAM_WRITEABLE(s) < ISIS_SUBTLV_MAX_SIZE) {
*min_len = ISIS_SUBTLV_MAX_SIZE;
@ -862,6 +1111,219 @@ static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
}
}
for (ALL_LIST_ELEMENTS_RO(exts->aslas, node, asla)) {
ret = pack_item_ext_subtlv_asla(asla, s, min_len);
if (ret < 0)
return ret;
}
return 0;
}
static int unpack_item_ext_subtlv_asla(uint16_t mtid, uint8_t subtlv_len,
struct stream *s, struct sbuf *log,
int indent,
struct isis_ext_subtlvs *exts)
{
/* Standard App Identifier Bit Flags/Length */
uint8_t sabm_flag_len;
/* User-defined App Identifier Bit Flags/Length */
uint8_t uabm_flag_len;
uint8_t sabm[ASLA_APP_IDENTIFIER_BIT_LENGTH] = {0};
uint8_t uabm[ASLA_APP_IDENTIFIER_BIT_LENGTH] = {0};
uint8_t readable;
uint8_t subsubtlv_type;
uint8_t subsubtlv_len;
size_t nb_groups;
struct isis_asla_subtlvs *asla;
if (subtlv_len < ISIS_SUBSUBTLV_HDR_SIZE) {
TLV_SIZE_MISMATCH(log, indent, "ASLA");
return -1;
}
asla = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*asla));
admin_group_init(&asla->ext_admin_group);
sabm_flag_len = stream_getc(s);
uabm_flag_len = stream_getc(s);
asla->legacy = CHECK_FLAG(sabm_flag_len, ASLA_LEGACY_FLAG);
asla->standard_apps_length = ASLA_APPS_LENGTH_MASK & sabm_flag_len;
asla->user_def_apps_length = ASLA_APPS_LENGTH_MASK & uabm_flag_len;
for (int i = 0; i < asla->standard_apps_length; i++)
sabm[i] = stream_getc(s);
for (int i = 0; i < asla->user_def_apps_length; i++)
uabm[i] = stream_getc(s);
asla->standard_apps = sabm[0];
asla->user_def_apps = uabm[0];
readable = subtlv_len - 4;
while (readable > 0) {
if (readable < ISIS_SUBSUBTLV_HDR_SIZE) {
TLV_SIZE_MISMATCH(log, indent, "ASLA Sub TLV");
return -1;
}
subsubtlv_type = stream_getc(s);
subsubtlv_len = stream_getc(s);
readable -= ISIS_SUBSUBTLV_HDR_SIZE;
switch (subsubtlv_type) {
case ISIS_SUBTLV_ADMIN_GRP:
if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
TLV_SIZE_MISMATCH(log, indent,
"ASLA Adm Group");
stream_forward_getp(s, subsubtlv_len);
} else {
asla->admin_group = stream_getl(s);
SET_SUBTLV(asla, EXT_ADM_GRP);
}
break;
case ISIS_SUBTLV_EXT_ADMIN_GRP:
nb_groups = subsubtlv_len / sizeof(uint32_t);
for (size_t i = 0; i < nb_groups; i++) {
uint32_t val = stream_getl(s);
admin_group_bulk_set(&asla->ext_admin_group,
val, i);
}
SET_SUBTLV(asla, EXT_EXTEND_ADM_GRP);
break;
case ISIS_SUBTLV_MAX_BW:
if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
TLV_SIZE_MISMATCH(log, indent,
"Maximum Bandwidth");
stream_forward_getp(s, subsubtlv_len);
} else {
asla->max_bw = stream_getf(s);
SET_SUBTLV(asla, EXT_MAX_BW);
}
break;
case ISIS_SUBTLV_MAX_RSV_BW:
if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
TLV_SIZE_MISMATCH(
log, indent,
"Maximum Reservable Bandwidth");
stream_forward_getp(s, subsubtlv_len);
} else {
asla->max_rsv_bw = stream_getf(s);
SET_SUBTLV(asla, EXT_MAX_RSV_BW);
}
break;
case ISIS_SUBTLV_UNRSV_BW:
if (subsubtlv_len != ISIS_SUBTLV_UNRSV_BW_SIZE) {
TLV_SIZE_MISMATCH(log, indent,
"Unreserved Bandwidth");
stream_forward_getp(s, subsubtlv_len);
} else {
for (int i = 0; i < MAX_CLASS_TYPE; i++)
asla->unrsv_bw[i] = stream_getf(s);
SET_SUBTLV(asla, EXT_UNRSV_BW);
}
break;
case ISIS_SUBTLV_TE_METRIC:
if (subsubtlv_len != ISIS_SUBTLV_TE_METRIC_SIZE) {
TLV_SIZE_MISMATCH(log, indent,
"Traffic Engineering Metric");
stream_forward_getp(s, subsubtlv_len);
} else {
asla->te_metric = stream_get3(s);
SET_SUBTLV(asla, EXT_TE_METRIC);
}
break;
/* Extended Metrics as defined in RFC 7810 */
case ISIS_SUBTLV_AV_DELAY:
if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
TLV_SIZE_MISMATCH(log, indent,
"Average Link Delay");
stream_forward_getp(s, subsubtlv_len);
} else {
asla->delay = stream_getl(s);
SET_SUBTLV(asla, EXT_DELAY);
}
break;
case ISIS_SUBTLV_MM_DELAY:
if (subsubtlv_len != ISIS_SUBTLV_MM_DELAY_SIZE) {
TLV_SIZE_MISMATCH(log, indent,
"Min/Max Link Delay");
stream_forward_getp(s, subsubtlv_len);
} else {
asla->min_delay = stream_getl(s);
asla->max_delay = stream_getl(s);
SET_SUBTLV(asla, EXT_MM_DELAY);
}
break;
case ISIS_SUBTLV_DELAY_VAR:
if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
TLV_SIZE_MISMATCH(log, indent,
"Delay Variation");
stream_forward_getp(s, subsubtlv_len);
} else {
asla->delay_var = stream_getl(s);
SET_SUBTLV(asla, EXT_DELAY_VAR);
}
break;
case ISIS_SUBTLV_PKT_LOSS:
if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
TLV_SIZE_MISMATCH(log, indent,
"Link Packet Loss");
stream_forward_getp(s, subsubtlv_len);
} else {
asla->pkt_loss = stream_getl(s);
SET_SUBTLV(asla, EXT_PKT_LOSS);
}
break;
case ISIS_SUBTLV_RES_BW:
if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
TLV_SIZE_MISMATCH(
log, indent,
"Unidirectional Residual Bandwidth");
stream_forward_getp(s, subsubtlv_len);
} else {
asla->res_bw = stream_getf(s);
SET_SUBTLV(asla, EXT_RES_BW);
}
break;
case ISIS_SUBTLV_AVA_BW:
if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
TLV_SIZE_MISMATCH(
log, indent,
"Unidirectional Available Bandwidth");
stream_forward_getp(s, subsubtlv_len);
} else {
asla->ava_bw = stream_getf(s);
SET_SUBTLV(asla, EXT_AVA_BW);
}
break;
case ISIS_SUBTLV_USE_BW:
if (subsubtlv_len != ISIS_SUBTLV_DEF_SIZE) {
TLV_SIZE_MISMATCH(
log, indent,
"Unidirectional Utilized Bandwidth");
stream_forward_getp(s, subsubtlv_len);
} else {
asla->use_bw = stream_getf(s);
SET_SUBTLV(asla, EXT_USE_BW);
}
break;
default:
zlog_debug("unknown (t,l)=(%u,%u)", subsubtlv_type,
subsubtlv_len);
stream_forward_getp(s, subsubtlv_len);
break;
}
readable -= subsubtlv_len;
}
listnode_add(exts->aslas, asla);
return 0;
}
@ -1209,6 +1671,13 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
}
break;
case ISIS_SUBTLV_ASLA:
if (unpack_item_ext_subtlv_asla(mtid, subtlv_len, s,
log, indent,
exts) < 0) {
sbuf_push(log, indent, "TLV parse error");
}
break;
default:
/* Skip unknown TLV */
stream_forward_getp(s, subtlv_len);
@ -5873,6 +6342,54 @@ void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
UNSET_SUBTLV(exts, EXT_LAN_ADJ_SID);
}
void isis_tlvs_del_asla_flex_algo(struct isis_ext_subtlvs *ext,
struct isis_asla_subtlvs *asla)
{
admin_group_term(&asla->ext_admin_group);
listnode_delete(ext->aslas, asla);
XFREE(MTYPE_ISIS_SUBTLV, asla);
}
struct isis_asla_subtlvs *
isis_tlvs_find_alloc_asla(struct isis_ext_subtlvs *ext, uint8_t standard_apps)
{
struct isis_asla_subtlvs *asla;
struct listnode *node;
if (!list_isempty(ext->aslas)) {
for (ALL_LIST_ELEMENTS_RO(ext->aslas, node, asla)) {
if (CHECK_FLAG(asla->standard_apps, standard_apps))
return asla;
}
}
asla = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(struct isis_asla_subtlvs));
admin_group_init(&asla->ext_admin_group);
SET_FLAG(asla->standard_apps, standard_apps);
SET_FLAG(asla->user_def_apps, standard_apps);
asla->standard_apps_length = ASLA_APP_IDENTIFIER_BIT_LENGTH;
asla->user_def_apps_length = ASLA_APP_IDENTIFIER_BIT_LENGTH;
listnode_add(ext->aslas, asla);
return asla;
}
void isis_tlvs_free_asla(struct isis_ext_subtlvs *ext, uint8_t standard_apps)
{
struct isis_asla_subtlvs *asla;
struct listnode *node;
if (!ext)
return;
for (ALL_LIST_ELEMENTS_RO(ext->aslas, node, asla)) {
if (!CHECK_FLAG(asla->standard_apps, standard_apps))
continue;
isis_tlvs_del_asla_flex_algo(ext, asla);
break;
}
}
void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
struct prefix_ipv4 *dest, uint32_t metric,
bool external,

View file

@ -400,6 +400,9 @@ enum isis_tlv_type {
ISIS_SUBTLV_AVA_BW = 38,
ISIS_SUBTLV_USE_BW = 39,
/* RFC 8919 */
ISIS_SUBTLV_ASLA = 16,
ISIS_SUBTLV_MAX = 40,
};
@ -434,6 +437,8 @@ enum ext_subtlv_size {
/* RFC 7308 */
ISIS_SUBTLV_EXT_ADMIN_GRP = 14,
ISIS_SUBSUBTLV_HDR_SIZE = 2,
ISIS_SUBTLV_MAX_SIZE = 180,
};
@ -441,6 +446,8 @@ enum ext_subtlv_size {
#define SET_SUBTLV(s, t) ((s->status) |= (t))
#define UNSET_SUBTLV(s, t) ((s->status) &= ~(t))
#define IS_SUBTLV(s, t) (s->status & t)
#define RESET_SUBTLV(s) (s->status = 0)
#define NO_SUBTLV(s) (s->status == 0)
#define EXT_DISABLE 0x000000
#define EXT_ADM_GRP 0x000001
@ -512,6 +519,45 @@ struct isis_ext_subtlvs {
/* Segment Routing Adjacency & LAN Adjacency Segment ID */
struct isis_item_list adj_sid;
struct isis_item_list lan_sid;
struct list *aslas;
};
/* RFC 8919 */
#define ISIS_SABM_FLAG_R 0x80 /* RSVP-TE */
#define ISIS_SABM_FLAG_S 0x40 /* Segment Routing Policy */
#define ISIS_SABM_FLAG_L 0x20 /* Loop-Free Alternate */
#define ISIS_SABM_FLAG_X 0x10 /* Flex-Algorithm - RFC9350 */
#define ASLA_APP_IDENTIFIER_BIT_LENGTH 1
#define ASLA_LEGACY_FLAG 0x80
#define ASLA_APPS_LENGTH_MASK 0x7f
struct isis_asla_subtlvs {
uint32_t status;
/* Application Specific Link Attribute - RFC 8919 */
bool legacy; /* L-Flag */
uint8_t standard_apps_length;
uint8_t user_def_apps_length;
uint8_t standard_apps;
uint8_t user_def_apps;
/* Sub-TLV list - rfc8919 section-3.1 */
uint32_t admin_group;
struct admin_group ext_admin_group; /* Res. Class/Color - RFC 7308 */
float max_bw; /* Maximum Bandwidth - RFC 5305 */
float max_rsv_bw; /* Maximum Reservable Bandwidth - RFC 5305 */
float unrsv_bw[8]; /* Unreserved Bandwidth - RFC 5305 */
uint32_t te_metric; /* Traffic Engineering Metric - RFC 5305 */
uint32_t delay; /* Average Link Delay - RFC 8570 */
uint32_t min_delay; /* Low Link Delay - RFC 8570 */
uint32_t max_delay; /* High Link Delay - RFC 8570 */
uint32_t delay_var; /* Link Delay Variation i.e. Jitter - RFC 8570 */
uint32_t pkt_loss; /* Unidirectional Link Packet Loss - RFC 8570 */
float res_bw; /* Unidirectional Residual Bandwidth - RFC 8570 */
float ava_bw; /* Unidirectional Available Bandwidth - RFC 8570 */
float use_bw; /* Unidirectional Utilized Bandwidth - RFC 8570 */
};
#define IS_COMPAT_MT_TLV(tlv_type) \
@ -542,6 +588,12 @@ struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size);
#define ISIS_MT_AT_MASK 0x4000
#endif
/* RFC 8919 */
#define ISIS_SABM_FLAG_R 0x80 /* RSVP-TE */
#define ISIS_SABM_FLAG_S 0x40 /* Segment Routing Policy */
#define ISIS_SABM_FLAG_L 0x20 /* Loop-Free Alternate */
#define ISIS_SABM_FLAG_X 0x10 /* Flex-Algorithm - RFC9350 */
void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd);
void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs,
struct list *addresses);
@ -606,6 +658,12 @@ void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
struct isis_lan_adj_sid *lan);
void isis_tlvs_del_asla_flex_algo(struct isis_ext_subtlvs *ext,
struct isis_asla_subtlvs *asla);
struct isis_asla_subtlvs *
isis_tlvs_find_alloc_asla(struct isis_ext_subtlvs *ext, uint8_t standard_apps);
void isis_tlvs_free_asla(struct isis_ext_subtlvs *ext, uint8_t standard_apps);
void isis_tlvs_add_oldstyle_reach(struct isis_tlvs *tlvs, uint8_t *id,
uint8_t metric);
void isis_tlvs_add_extended_reach(struct isis_tlvs *tlvs, uint16_t mtid,