diff options
author | Olivier Dugeon <olivier.dugeon@orange.com> | 2018-01-18 19:11:11 +0100 |
---|---|---|
committer | Olivier Dugeon <olivier.dugeon@orange.com> | 2018-01-18 19:11:11 +0100 |
commit | cf9b9f77f638923f5a44fdd14ce2725631ffa526 (patch) | |
tree | 70b0b5c8181c23a4fd8faf5750e80083a422c728 /ospfd/ospf_ri.c | |
parent | Merge pull request #1626 from LabNConsulting/working/master/vnc-config (diff) | |
download | frr-cf9b9f77f638923f5a44fdd14ce2725631ffa526.tar.xz frr-cf9b9f77f638923f5a44fdd14ce2725631ffa526.zip |
OSPFD: Add Experimental Segment Routing support
This is an implementation of draft-ietf-ospf-segment-routing-extensions-24
and RFC7684 for Extended Link & Prefix Opaque LSA.
Look to doc/OSPF_SR.rst for implementation details & known limitations.
New files:
- ospfd/ospf_sr.h: Segment Routing structure definition (SubTLVs + SRDB)
- ospfd/ospf_sr.c: Main functions for Segment Routing support
- ospfd/ospf_ext.h: TLVs and SubTLVs definition for RFC7684
- ospfd/ospf_ext.c: RFC7684 Extended Link / Prefix implementation
- doc/OSPF-SRr.rst: Documentation
Modified Files:
- doc/ospfd.texi: Add new Segment Routing CLI command definition
- lib/command.h: Add new string command for Segment Routing CLI
- lib/mpls.h: Add default value for SRGB
- lib/route_types.txt: Add new OSPF Segment Routing route type
- ospfd/ospf_dump.[c,h]: Add OSPF SR debug
- ospfd/ospf_memory.[c,h]: Add new Segment Routing memory type
- ospfd/ospf_opaque.[c,h]: Add ospf_sr_init() starting function
- ospfd/ospf_ri.c: Add new functions to Set/Get Segment Routing TLVs
Add new ospf_router_info_lsa_upadte() to send Opaque LSA to ospf_sr.c()
- ospfd/ospf_ri.h: Add new Router Information SR SubTLVs
- ospfd/ospf_spf.c: Add new scheduler when running SPF to trigger
update of NHLFE
- ospfd/ospfd.h: Add new thread for Segment Routing scheduler
- ospfd/subdir.am: Add new files
- vtysh/Makefile.am: Add new ospf_sr.c file for vtysh
- zebra/kernel_netlink.c: Add new OSPF_SR route type
- zebra/rt_netlink.[c,h]: Add new OSPF_SR route type
- zebra/zebra_mpls.h: Add new OSPF_SR route type
Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
Diffstat (limited to 'ospfd/ospf_ri.c')
-rw-r--r-- | ospfd/ospf_ri.c | 425 |
1 files changed, 370 insertions, 55 deletions
diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index ead692343..0a6917dce 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -3,9 +3,8 @@ * with support of RFC5088 PCE Capabilites announcement * * Module name: Router Information - * Version: 0.99.22 - * Created: 2012-02-01 by Olivier Dugeon - * Copyright (C) 2012 Orange Labs http://www.orange.com/ + * Author: Olivier Dugeon <olivier.dugeon@orange.com> + * Copyright (C) 2012 - 2017 Orange Labs http://www.orange.com/ * * This file is part of GNU Quagga. * @@ -39,6 +38,7 @@ #include "thread.h" #include "hash.h" #include "sockunion.h" /* for inet_aton() */ +#include "mpls.h" #include "ospfd/ospfd.h" #include "ospfd/ospf_interface.h" @@ -55,8 +55,8 @@ #include "ospfd/ospf_route.h" #include "ospfd/ospf_ase.h" #include "ospfd/ospf_zebra.h" +#include "ospfd/ospf_sr.h" #include "ospfd/ospf_ri.h" -#include "ospfd/ospf_te.h" /* Store Router Information PCE TLV and SubTLV in network byte order. */ struct ospf_pce_info { @@ -69,6 +69,20 @@ struct ospf_pce_info { struct ri_pce_subtlv_cap_flag pce_cap_flag; }; +/* Store Router Information Segment Routing TLV and SubTLV in network byte order. */ +struct ospf_ri_sr_info { + bool enabled; + /* Algorithms supported by the node */ + struct ri_sr_tlv_sr_algorithm algo; + /* + * Segment Routing Global Block i.e. label range + * Only one range supported in this code + */ + struct ri_sr_tlv_sid_label_range range; + /* Maximum SID Depth supported by the node */ + struct ri_sr_tlv_node_msd msd; +}; + /* Following structure are internal use only. */ struct ospf_router_info { bool enabled; @@ -77,7 +91,7 @@ struct ospf_router_info { u_int8_t scope; /* Flags to manage this router information. */ -#define RIFLG_LSA_ENGAGED 0x1 +#define RIFLG_LSA_ENGAGED 0x1 #define RIFLG_LSA_FORCED_REFRESH 0x2 u_int32_t flags; @@ -90,6 +104,9 @@ struct ospf_router_info { /* Store PCE capability LSA */ struct ospf_pce_info pce_info; + + /* Store SR capability LSA */ + struct ospf_ri_sr_info sr_info; }; /* @@ -113,15 +130,19 @@ static int ospf_router_info_lsa_originate(void *arg); static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa); static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode); static void ospf_router_info_register_vty(void); +static int ospf_router_info_lsa_update(struct ospf_lsa *lsa); static void del_pce_info(void *val); int ospf_router_info_init(void) { + zlog_info("RI -> Initialize Router Information"); + memset(&OspfRI, 0, sizeof(struct ospf_router_info)); OspfRI.enabled = false; OspfRI.registered = 0; OspfRI.scope = OSPF_OPAQUE_AS_LSA; + OspfRI.area_id.s_addr = 0; OspfRI.flags = 0; /* Initialize pce domain and neighbor list */ @@ -131,6 +152,9 @@ int ospf_router_info_init(void) OspfRI.pce_info.pce_neighbor = list_new(); OspfRI.pce_info.pce_neighbor->del = del_pce_info; + /* Initialize Segment Routing information structure */ + OspfRI.sr_info.enabled = false; + ospf_router_info_register_vty(); return 0; @@ -143,19 +167,22 @@ static int ospf_router_info_register(u_int8_t scope) if (OspfRI.registered) return rc; - zlog_info("Register Router Information with scope %s(%d)", + zlog_info("RI -> Register Router Information with scope %s(%d)", scope == OSPF_OPAQUE_AREA_LSA ? "Area" : "AS", scope); rc = ospf_register_opaque_functab( scope, OPAQUE_TYPE_ROUTER_INFORMATION_LSA, NULL, /* new interface */ NULL, /* del interface */ - ospf_router_info_ism_change, ospf_router_info_nsm_change, + ospf_router_info_ism_change, + ospf_router_info_nsm_change, ospf_router_info_config_write_router, NULL, /* Config. write interface */ NULL, /* Config. write debug */ - ospf_router_info_show_info, ospf_router_info_lsa_originate, - ospf_router_info_lsa_refresh, NULL, /* new_lsa_hook */ - NULL); /* del_lsa_hook */ + ospf_router_info_show_info, + ospf_router_info_lsa_originate, + ospf_router_info_lsa_refresh, + ospf_router_info_lsa_update, + NULL); /* del_lsa_hook */ if (rc != 0) { zlog_warn( @@ -204,6 +231,20 @@ static void del_pce_info(void *val) return; } +/* Catch RI LSA flooding Scope for ospf_ext.[h,c] code */ +struct scope_info ospf_router_info_get_flooding_scope(void) +{ + struct scope_info flooding_scope; + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) { + flooding_scope.scope = OSPF_OPAQUE_AS_LSA; + flooding_scope.area_id.s_addr = 0; + return flooding_scope; + } + flooding_scope.scope = OSPF_OPAQUE_AREA_LSA; + flooding_scope.area_id.s_addr = OspfRI.area_id.s_addr; + return flooding_scope; +} + /*------------------------------------------------------------------------* * Followings are control functions for ROUTER INFORMATION parameters *management. @@ -399,6 +440,84 @@ static void set_pce_cap_flag(u_int32_t cap, struct ospf_pce_info *pce) return; } +/* Segment Routing TLV setter */ + +/* Algorithm SubTLV - section 3.1 */ +static void set_sr_algorithm(u_int8_t algo) +{ + + OspfRI.sr_info.algo.value[0] = algo; + for (int i = 1; i < ALGORITHM_COUNT; i++) + OspfRI.sr_info.algo.value[i] = SR_ALGORITHM_UNSET; + + /* Set TLV type and length == only 1 Algorithm */ + TLV_TYPE(OspfRI.sr_info.algo) = htons(RI_SR_TLV_SR_ALGORITHM); + TLV_LEN(OspfRI.sr_info.algo) = htons(sizeof(u_int8_t)); + + return; +} + +/* unset Aglogithm SubTLV */ +static void unset_sr_algorithm(u_int8_t algo) +{ + + for (int i = 0; i < ALGORITHM_COUNT; i++) + OspfRI.sr_info.algo.value[i] = SR_ALGORITHM_UNSET; + + /* Unset TLV type and length */ + TLV_TYPE(OspfRI.sr_info.algo) = htons(0); + TLV_LEN(OspfRI.sr_info.algo) = htons(0); + + return; +} + +/* Segment Routing Global Block SubTLV - section 3.2 */ +static void set_sr_sid_label_range(struct sr_srgb srgb) +{ + /* Set Header */ + TLV_TYPE(OspfRI.sr_info.range) = htons(RI_SR_TLV_SID_LABEL_RANGE); + TLV_LEN(OspfRI.sr_info.range) = + htons(SUBTLV_SID_LABEL_SIZE + sizeof(u_int32_t)); + /* Set Range Size */ + OspfRI.sr_info.range.size = htonl(SET_RANGE_SIZE(srgb.range_size)); + /* Set Lower bound label SubTLV */ + TLV_TYPE(OspfRI.sr_info.range.lower) = htons(SUBTLV_SID_LABEL); + TLV_LEN(OspfRI.sr_info.range.lower) = htons(SID_RANGE_LABEL_LENGTH); + OspfRI.sr_info.range.lower.value = htonl(SET_LABEL(srgb.lower_bound)); + + return; +} + +/* Unset this SRGB SubTLV */ +static void unset_sr_sid_label_range() +{ + + TLV_TYPE(OspfRI.sr_info.range) = htons(0); + TLV_LEN(OspfRI.sr_info.range) = htons(0); + TLV_TYPE(OspfRI.sr_info.range.lower) = htons(0); + TLV_LEN(OspfRI.sr_info.range.lower) = htons(0); + + return; +} + +/* Set Maximum Stack Depth for this router */ +static void set_sr_node_msd(u_int8_t msd) +{ + TLV_TYPE(OspfRI.sr_info.msd) = htons(RI_SR_TLV_NODE_MSD); + TLV_LEN(OspfRI.sr_info.msd) = htons(sizeof(u_int32_t)); + OspfRI.sr_info.msd.value = msd; + + return; +} + +/* Unset this router MSD */ +static void unset_sr_node_msd() +{ + TLV_TYPE(OspfRI.sr_info.msd) = htons(0); + TLV_LEN(OspfRI.sr_info.msd) = htons(0); + + return; +} static void unset_param(struct tlv_header *tlv) { @@ -466,11 +585,62 @@ static int is_mandated_params_set(struct ospf_router_info ori) && (ntohs(ori.pce_info.pce_cap_flag.header.type) == 0)) return rc; + if ((ori.sr_info.enabled) && (ntohs(TLV_TYPE(ori.sr_info.algo)) == 0) + && (ntohs(TLV_TYPE(ori.sr_info.range)) == 0)) + return rc; + rc = 1; return rc; } +/* + * Used by Segment Routing to set new TLVs and Sub-TLVs values + * + * @param enable To activate or not Segment Routing router Information flooding + * @param size Size of Label Range i.e. SRGB size + * @param lower Lower bound of the Label Range i.e. SRGB first label + * @param msd Maximum label Stack Depth suported by the router + * + * @return none + */ +void ospf_router_info_update_sr(bool enable, struct sr_srgb srgb, u_int8_t msd) +{ + + /* First activate and initialize Router Information is necessary */ + if (!OspfRI.enabled) { + OspfRI.enabled = true; + initialize_params(&OspfRI); + } + + if (IS_DEBUG_OSPF_SR) + zlog_debug("RI-> %s Routing Information for Segment Routing", + enable ? "Enable" : "Disable"); + + /* Unset or Set SR parameters */ + if (!enable) { + unset_sr_algorithm(SR_ALGORITHM_SPF); + unset_sr_sid_label_range(); + unset_sr_node_msd(); + OspfRI.sr_info.enabled = false; + } else { + // Only SR_ALGORITHM_SPF is supported + set_sr_algorithm(SR_ALGORITHM_SPF); + set_sr_sid_label_range(srgb); + if (msd != 0) + set_sr_node_msd(msd); + else + unset_sr_node_msd(); + OspfRI.sr_info.enabled = true; + } + + /* Refresh if already engaged or originate RI LSA */ + if (CHECK_FLAG(OspfRI.flags, RIFLG_LSA_ENGAGED)) + ospf_router_info_lsa_schedule(REFRESH_THIS_LSA); + else + ospf_router_info_lsa_schedule(REORIGINATE_THIS_LSA); +} + /*------------------------------------------------------------------------* * Followings are callback functions against generic Opaque-LSAs handling. *------------------------------------------------------------------------*/ @@ -519,12 +689,22 @@ static void ospf_router_info_lsa_body_set(struct stream *s) /* Build Router Information TLV */ build_tlv(s, &OspfRI.router_cap.header); - /* Compute PCE Info header first */ - set_pce_header (&OspfRI.pce_info); + /* Build Segment Routing TLVs if enabled */ + if (OspfRI.sr_info.enabled) { + /* Build Algorithm TLV */ + build_tlv(s, &TLV_HDR(OspfRI.sr_info.algo)); + /* Build SRGB TLV */ + build_tlv(s, &TLV_HDR(OspfRI.sr_info.range)); + /* Build MSD TLV */ + build_tlv(s, &TLV_HDR(OspfRI.sr_info.msd)); + } /* Add RI PCE TLV if it is set */ if (OspfRI.pce_info.enabled) { + /* Compute PCE Info header first */ + set_pce_header (&OspfRI.pce_info); + /* Build PCE TLV */ build_tlv_header(s, &OspfRI.pce_info.pce_header.header); @@ -855,6 +1035,38 @@ static void ospf_router_info_lsa_schedule(enum lsa_opcode opcode) return; } +/* Callback to handle Segment Routing information */ +static int ospf_router_info_lsa_update(struct ospf_lsa *lsa) +{ + + /* Sanity Check */ + if (lsa == NULL) { + zlog_warn("OSPF-RI (ospf_router_info_lsa_update): Abort! LSA is NULL"); + return -1; + } + + /* Check if it is not my LSA */ + if (IS_LSA_SELF(lsa)) + return 0; + + /* Process only Router Information LSA */ + if (GET_OPAQUE_TYPE( + ntohl(lsa->data->id.s_addr)) != OPAQUE_TYPE_ROUTER_INFORMATION_LSA) + return 0; + + /* Check if Router Info & Segment Routing are enable */ + if (!OspfRI.enabled || !OspfRI.sr_info.enabled) + return 0; + + /* Call Segment Routing LSA update or deletion */ + if (!IS_LSA_MAXAGE(lsa)) + ospf_sr_ri_lsa_update(lsa); + else + ospf_sr_ri_lsa_delete(lsa); + + return 0; +} + /*------------------------------------------------------------------------* * Followings are vty session control functions. *------------------------------------------------------------------------*/ @@ -1021,6 +1233,98 @@ static u_int16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri, return sum; } +/* Display Segment Routing Algorithm TLV information */ +static u_int16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh) +{ + struct ri_sr_tlv_sr_algorithm *algo = + (struct ri_sr_tlv_sr_algorithm *)tlvh; + int i; + if (vty != NULL) { + vty_out(vty, " Segment Routing Algorithm TLV:\n"); + for (i = 0; i < ntohs(algo->header.length); i++) { + switch (algo->value[i]) { + case 0: + vty_out(vty, " Algorithm %d: SPF\n", i); + break; + case 1: + vty_out(vty, " Algorithm %d: Strict SPF\n", + i); + break; + default: + vty_out(vty, + " Algorithm %d: Unknown value %d\n", i, + algo->value[i]); + break; + } + } + } + + else { + zlog_debug(" Segment Routing Algorithm TLV:\n"); + for (i = 0; i < ntohs(algo->header.length); i++) + switch (algo->value[i]) { + case 0: + zlog_debug(" Algorithm %d: SPF\n", i); + break; + case 1: + zlog_debug(" Algorithm %d: Strict SPF\n", i); + break; + default: + zlog_debug( + " Algorithm %d: Unknown value %d\n", + i, algo->value[i]); + break; + } + } + + return TLV_SIZE(tlvh); +} + +/* Display Segment Routing SID/Label Range TLV information */ +static u_int16_t show_vty_sr_range(struct vty *vty, struct tlv_header *tlvh) +{ + struct ri_sr_tlv_sid_label_range *range = + (struct ri_sr_tlv_sid_label_range *)tlvh; + + if (vty != NULL) { + vty_out(vty, + " Segment Routing Range TLV:\n" + " Range Size = %d\n" + " SID Label = %d\n\n", + GET_RANGE_SIZE(ntohl(range->size)), + GET_LABEL(ntohl(range->lower.value))); + } else { + zlog_debug( + " Segment Routing Range TLV:\n" + " Range Size = %d\n" + " SID Label = %d\n\n", + GET_RANGE_SIZE(ntohl(range->size)), + GET_LABEL(ntohl(range->lower.value))); + } + + return TLV_SIZE(tlvh); +} + +/* Display Segment Routing Maximum Stack Depth TLV information */ +static u_int16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh) +{ + struct ri_sr_tlv_node_msd *msd = (struct ri_sr_tlv_node_msd *)tlvh; + + if (vty != NULL) { + vty_out(vty, + " Segment Routing MSD TLV:\n" + " Node Maximum Stack Depth = %d\n", + msd->value); + } else { + zlog_debug( + " Segment Routing MSD TLV:\n" + " Node Maximum Stack Depth = %d\n", + msd->value); + } + + return TLV_SIZE(tlvh); +} + static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa) { struct lsa_header *lsah = (struct lsa_header *)lsa->data; @@ -1041,6 +1345,16 @@ static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa) sum += TLV_HDR_SIZE; sum += show_vty_pce_info(vty, tlvh, length - sum); break; + case RI_SR_TLV_SR_ALGORITHM: + sum += show_vty_sr_algorithm(vty, tlvh); + break; + case RI_SR_TLV_SID_LABEL_RANGE: + sum += show_vty_sr_range(vty, tlvh); + break; + case RI_SR_TLV_NODE_MSD: + sum += show_vty_sr_msd(vty, tlvh); + break; + default: sum += show_vty_unknown_tlv(vty, tlvh); break; @@ -1058,53 +1372,54 @@ static void ospf_router_info_config_write_router(struct vty *vty) struct ri_pce_subtlv_neighbor *neighbor; struct in_addr tmp; - if (OspfRI.enabled) { - if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) - vty_out(vty, " router-info as\n"); - else - vty_out(vty, " router-info area %s\n", - inet_ntoa(OspfRI.area_id)); - - if (OspfRI.pce_info.enabled) { - - if (pce->pce_address.header.type != 0) - vty_out(vty, " pce address %s\n", - inet_ntoa(pce->pce_address.address.value)); - - if (pce->pce_cap_flag.header.type != 0) - vty_out(vty, " pce flag 0x%x\n", - ntohl(pce->pce_cap_flag.value)); - - for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) { - if (domain->header.type != 0) { - if (domain->type == PCE_DOMAIN_TYPE_AREA) { - tmp.s_addr = domain->value; - vty_out(vty, " pce domain area %s\n", - inet_ntoa(tmp)); - } else { - vty_out(vty, " pce domain as %d\n", - ntohl(domain->value)); - } + if (!OspfRI.enabled) + return; + + if (OspfRI.scope == OSPF_OPAQUE_AS_LSA) + vty_out(vty, " router-info as\n"); + else + vty_out(vty, " router-info area %s\n", + inet_ntoa(OspfRI.area_id)); + + if (OspfRI.pce_info.enabled) { + + if (pce->pce_address.header.type != 0) + vty_out(vty, " pce address %s\n", + inet_ntoa(pce->pce_address.address.value)); + + if (pce->pce_cap_flag.header.type != 0) + vty_out(vty, " pce flag 0x%x\n", + ntohl(pce->pce_cap_flag.value)); + + for (ALL_LIST_ELEMENTS_RO(pce->pce_domain, node, domain)) { + if (domain->header.type != 0) { + if (domain->type == PCE_DOMAIN_TYPE_AREA) { + tmp.s_addr = domain->value; + vty_out(vty, " pce domain area %s\n", + inet_ntoa(tmp)); + } else { + vty_out(vty, " pce domain as %d\n", + ntohl(domain->value)); } } + } - for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) { - if (neighbor->header.type != 0) { - if (neighbor->type == PCE_DOMAIN_TYPE_AREA) { - tmp.s_addr = neighbor->value; - vty_out(vty, " pce neighbor area %s\n", - inet_ntoa(tmp)); - } else { - vty_out(vty, " pce neighbor as %d\n", - ntohl(neighbor->value)); - } + for (ALL_LIST_ELEMENTS_RO(pce->pce_neighbor, node, neighbor)) { + if (neighbor->header.type != 0) { + if (neighbor->type == PCE_DOMAIN_TYPE_AREA) { + tmp.s_addr = neighbor->value; + vty_out(vty, " pce neighbor area %s\n", + inet_ntoa(tmp)); + } else { + vty_out(vty, " pce neighbor as %d\n", + ntohl(neighbor->value)); } } - - if (pce->pce_scope.header.type != 0) - vty_out(vty, " pce scope 0x%x\n", - ntohl(OspfRI.pce_info.pce_scope.value)); } + + if (pce->pce_scope.header.type != 0) + vty_out(vty, " pce scope 0x%x\n", + ntohl(OspfRI.pce_info.pce_scope.value)); } return; } @@ -1539,7 +1854,7 @@ DEFUN (show_ip_opsf_router_info_pce, struct ri_pce_subtlv_domain *domain; struct ri_pce_subtlv_neighbor *neighbor; - if (OspfRI.enabled) { + if ((OspfRI.enabled) && (OspfRI.pce_info.enabled)) { vty_out(vty, "--- PCE parameters ---\n"); if (pce->pce_address.header.type != 0) @@ -1568,7 +1883,7 @@ DEFUN (show_ip_opsf_router_info_pce, } else { vty_out(vty, - " Router Information is disabled on this router\n"); + " PCE info is disabled on this router\n"); } return CMD_SUCCESS; |