diff options
44 files changed, 875 insertions, 364 deletions
diff --git a/.travis.yml b/.travis.yml index 010292bb6a..32b686c00e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,14 +5,14 @@ services: - docker jobs: include: - # - script: - # - docker/centos-7/build.sh - # - docker images - # name: centos7 - # - script: - # - docker/centos-8/build.sh - # - docker images - # name: centos8 + - script: + - docker/centos-7/build.sh + - docker images + name: centos7 + - script: + - docker/centos-8/build.sh + - docker images + name: centos8 - script: - sudo apt install -y linux-modules-extra-$(uname -r) - docker build -t frr-ubuntu18:latest -f docker/ubuntu18-ci/Dockerfile . diff --git a/Makefile.am b/Makefile.am index a5101df2f0..a38029dcfa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -11,6 +11,11 @@ AM_CFLAGS = \ $(SAN_FLAGS) \ $(WERROR) \ # end +AM_CXXFLAGS = \ + $(AC_CXXFLAGS) \ + $(LIBYANG_CFLAGS) \ + $(WERROR) \ + # end # CPPFLAGS_BASE does not contain the include path for overriding assert.h, # therefore should be used in tools that do *not* link libfrr or do not want diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index f3857162c3..860c5fd382 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -572,7 +572,9 @@ static int bgp_accept(struct thread *thread) peer->doppelganger = peer1; peer1->doppelganger = peer; peer->fd = bgp_sock; - vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer)); + frr_with_privs(&bgpd_privs) { + vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer)); + } bgp_peer_reg_with_nht(peer); bgp_fsm_change_status(peer, Active); BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 63214c5676..2bf57130be 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2609,6 +2609,9 @@ static void bgp_zebra_connected(struct zclient *zclient) zclient_num_connects++; /* increment even if not responding */ + /* Send the client registration */ + bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); + /* At this point, we may or may not have BGP instances configured, but * we're only interested in the default VRF (others wouldn't have learnt * the VRF from Zebra yet.) @@ -2619,9 +2622,6 @@ static void bgp_zebra_connected(struct zclient *zclient) bgp_zebra_instance_register(bgp); - /* Send the client registration */ - bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, bgp->vrf_id); - /* tell label pool that zebra is connected */ bgp_lp_event_zebra_up(); diff --git a/configure.ac b/configure.ac index f84a3d3c5e..6ed438ace0 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ([2.69]) -AC_INIT([frr], [7.7-dev], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [8.1-dev], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST([PACKAGE_URL]) PACKAGE_FULLNAME="FRRouting" diff --git a/doc/developer/building-libyang.rst b/doc/developer/building-libyang.rst index a447f58309..3b33eb3879 100644 --- a/doc/developer/building-libyang.rst +++ b/doc/developer/building-libyang.rst @@ -10,7 +10,7 @@ The FRR project builds some binary ``libyang`` packages. RPM packages are at our `RPM repository <https://rpm.frrouting.org>`_. DEB packages are available as CI artifacts `here -<https://ci1.netdef.org/browse/LIBYANG-LIBYANG-V2/latestSuccessful/artifact>`_. +<https://ci1.netdef.org/browse/LIBYANG-LIBYANGV2/latestSuccessful/artifact>`_. .. warning:: diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index b4ddec10c9..58b9c36e01 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -1247,7 +1247,6 @@ the command :clicmd:`show pony` would be documented as follows: .. code-block:: rest - .. index:: show pony .. clicmd:: show pony Prints an ASCII pony. Example output::: diff --git a/doc/user/eigrpd.rst b/doc/user/eigrpd.rst index 573e2ca2e4..3650792a3e 100644 --- a/doc/user/eigrpd.rst +++ b/doc/user/eigrpd.rst @@ -152,8 +152,7 @@ Show EIGRP Information Display the list of interfaces associated with a particular eigrp instance. -..index:: show ip eigrp [vrf NAME] neighbor -..clicmd:: show ip eigrp [vrf NAME] neighbor +.. clicmd:: show ip eigrp [vrf NAME] neighbor Display the list of neighbors that have been established within a particular eigrp instance. diff --git a/doc/user/nhrpd.rst b/doc/user/nhrpd.rst index cbbc2dc10a..54527a0c9a 100644 --- a/doc/user/nhrpd.rst +++ b/doc/user/nhrpd.rst @@ -198,13 +198,11 @@ original multicast packet. iptables -A OUTPUT -d 224.0.0.0/24 -o gre1 -j NFLOG --nflog-group 2 iptables -A OUTPUT -d 224.0.0.0/24 -o gre1 -j DROP -.. index:: nhrp multicast-nflog-group (1-65535) .. clicmd:: nhrp multicast-nflog-group (1-65535) Sets the nflog group that nhrpd will listen on for multicast packets. This value must match the nflog-group value set in the iptables rule. -.. index:: ip nhrp map multicast A.B.C.D|X:X::X:X A.B.C.D|dynamic .. clicmd:: ip nhrp map multicast A.B.C.D|X:X::X:X A.B.C.D|dynamic Sends multicast packets to the specified NBMA address. If dynamic is diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index d7f4a3303e..2b478d334e 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -139,7 +139,6 @@ Redistribute routes to OSPF6 Redistribute routes from other protocols into OSPFv3. -.. index:: default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}] .. clicmd:: default-information originate [{always|metric (0-16777214)|metric-type (1-2)|route-map WORD}] The command injects default route in the connected areas. The always diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index ba9917f72f..b321d99ad8 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -855,13 +855,11 @@ Traffic Engineering flood in AREA <area-id> with Opaque Type-10, respectively in AS with Opaque Type-11. In all case, Opaque-LSA TLV=6. -.. index:: mpls-te export .. clicmd:: no mpls-te export Export Traffic Engineering Data Base to other daemons through the ZAPI Opaque Link State messages. -.. index:: show ip ospf mpls-te interface .. clicmd:: show ip ospf mpls-te interface .. clicmd:: show ip ospf mpls-te interface INTERFACE @@ -872,16 +870,12 @@ Traffic Engineering Show Traffic Engineering router parameters. -.. index:: show ip ospf mpls-te database [verbose|json] .. clicmd:: show ip ospf mpls-te database [verbose|json] -.. index:: show ip ospf mpls-te database vertex [self-originate|adv-router ADV-ROUTER] [verbose|json] .. clicmd:: show ip ospf mpls-te database vertex [self-originate|adv-router ADV-ROUTER] [verbose|json] -.. index:: show ip ospf mpls-te database edge [A.B.C.D] [verbose|json] .. clicmd:: show ip ospf mpls-te database edge [A.B.C.D] [verbose|json] -.. index:: show ip ospf mpls-te database subnet [A.B.C.D/M] [verbose|json] .. clicmd:: show ip ospf mpls-te database subnet [A.B.C.D/M] [verbose|json] Show Traffic Engineering Database diff --git a/doc/user/pathd.rst b/doc/user/pathd.rst index c40efffc88..4c7611bc04 100644 --- a/doc/user/pathd.rst +++ b/doc/user/pathd.rst @@ -149,7 +149,7 @@ Configuration Commands Delete or start a dynamic candidate path definition. -.. clicmd:: affinity {exclude-any|include-any|include-all} BITPATTERN +.. clicmd:: affinity <exclude-any|include-any|include-all> BITPATTERN Delete or specify an affinity constraint for a dynamic candidate path. diff --git a/docker/centos-7/Dockerfile b/docker/centos-7/Dockerfile index d2ec9f974b..748b5345a1 100644 --- a/docker/centos-7/Dockerfile +++ b/docker/centos-7/Dockerfile @@ -5,8 +5,8 @@ RUN yum install -y rpm-build autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig \ json-c-devel pam-devel bison flex pytest c-ares-devel \ python3-devel python3-sphinx systemd-devel libcap-devel \ - https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-7-x86_64-Packages/libyang1-1.0.184-0.x86_64.rpm \ - https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-7-x86_64-Packages/libyang-devel-1.0.184-0.x86_64.rpm \ + https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-7-x86_64-Packages/libyang2-2.0.0.10.g2eb910e4-1.el7.x86_64.rpm \ + https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-7-x86_64-Packages/libyang2-devel-2.0.0.10.g2eb910e4-1.el7.x86_64.rpm \ https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm \ https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-devel-0.7.0-1.el7.centos.x86_64.rpm @@ -32,7 +32,7 @@ RUN echo '%_smp_mflags %( echo "-j$(/usr/bin/getconf _NPROCESSORS_ONLN)"; )' >> # This stage installs frr from the rpm FROM centos:centos7 RUN mkdir -p /pkgs/rpm \ - && yum install -y https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-7-x86_64-Packages/libyang1-1.0.184-0.x86_64.rpm \ + && yum install -y https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-7-x86_64-Packages/libyang2-2.0.0.10.g2eb910e4-1.el7.x86_64.rpm \ https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm COPY --from=centos-7-builder /rpmbuild/RPMS/ /pkgs/rpm/ diff --git a/docker/centos-8/Dockerfile b/docker/centos-8/Dockerfile index 104501aabc..e273be055b 100644 --- a/docker/centos-8/Dockerfile +++ b/docker/centos-8/Dockerfile @@ -5,8 +5,8 @@ RUN dnf install --enablerepo=powertools -y rpm-build git autoconf pcre-devel \ automake libtool make readline-devel texinfo net-snmp-devel pkgconfig \ groff pkgconfig json-c-devel pam-devel bison flex python3-pytest \ c-ares-devel python3-devel python3-sphinx systemd-devel libcap-devel platform-python-devel \ - https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-8-x86_64-Packages/libyang1-1.0.184-0.x86_64.rpm \ - https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-8-x86_64-Packages/libyang-devel-1.0.184-0.x86_64.rpm \ + https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-8-x86_64-Packages/libyang2-2.0.0.10.g2eb910e4-1.el8.x86_64.rpm \ + https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-8-x86_64-Packages/libyang2-devel-2.0.0.10.g2eb910e4-1.el8.x86_64.rpm \ https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm \ https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-devel-0.7.0-1.el7.centos.x86_64.rpm @@ -33,7 +33,7 @@ RUN echo '%_smp_mflags %( echo "-j$(/usr/bin/getconf _NPROCESSORS_ONLN)"; )' >> # This stage installs frr from the rpm FROM centos:centos8 RUN mkdir -p /pkgs/rpm \ - && yum install -y https://ci1.netdef.org/artifact/LIBYANG-LY1REL/shared/build-4/CentOS-8-x86_64-Packages/libyang1-1.0.184-0.x86_64.rpm \ + && yum install -y https://ci1.netdef.org/artifact/LIBYANG-LIBYANGV2/shared/build-2/CentOS-8-x86_64-Packages/libyang2-2.0.0.10.g2eb910e4-1.el8.x86_64.rpm \ https://ci1.netdef.org/artifact/RPKI-RTRLIB/shared/build-110/CentOS-7-x86_64-Packages/librtr-0.7.0-1.el7.centos.x86_64.rpm COPY --from=centos-8-builder /rpmbuild/RPMS/ /pkgs/rpm/ diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c index dfc865162f..fa2f9a7669 100644 --- a/isisd/isis_snmp.c +++ b/isisd/isis_snmp.c @@ -616,11 +616,44 @@ static uint8_t isis_null_sysid[ISIS_SYS_ID_LEN]; #define ISIS_SNMP_ADJ_STATE_UP (3) #define ISIS_SNMP_ADJ_STATE_FAILED (4) +static inline uint32_t isis_snmp_adj_state(enum isis_adj_state state) +{ + switch (state) { + case ISIS_ADJ_UNKNOWN: + return ISIS_SNMP_ADJ_STATE_DOWN; + case ISIS_ADJ_INITIALIZING: + return ISIS_SNMP_ADJ_STATE_INITIALIZING; + case ISIS_ADJ_UP: + return ISIS_SNMP_ADJ_STATE_UP; + case ISIS_ADJ_DOWN: + return ISIS_SNMP_ADJ_STATE_FAILED; + } + + return 0; /* not reached */ +} + #define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1 (1) #define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L2 (2) #define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1_L2 (3) #define ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN (4) +static inline uint32_t isis_snmp_adj_neightype(enum isis_system_type type) +{ + switch (type) { + case ISIS_SYSTYPE_UNKNOWN: + case ISIS_SYSTYPE_ES: + return ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN; + case ISIS_SYSTYPE_IS: + return ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1_L2; + case ISIS_SYSTYPE_L1_IS: + return ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1; + case ISIS_SYSTYPE_L2_IS: + return ISIS_SNMP_ADJ_NEIGHTYPE_IS_L2; + } + + return 0; /* not reached */ +} + #define ISIS_SNMP_INET_TYPE_V4 (1) #define ISIS_SNMP_INET_TYPE_V6 (2) @@ -2510,23 +2543,7 @@ static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name, switch (v->magic) { case ISIS_ISADJ_STATE: - - switch (adj->adj_state) { - case ISIS_ADJ_UNKNOWN: - case ISIS_ADJ_DOWN: - val = ISIS_SNMP_ADJ_STATE_DOWN; - break; - - case ISIS_ADJ_INITIALIZING: - val = ISIS_SNMP_ADJ_STATE_INITIALIZING; - break; - - case ISIS_ADJ_UP: - val = ISIS_SNMP_ADJ_STATE_UP; - break; - } - - return SNMP_INTEGER(val); + return SNMP_INTEGER(isis_snmp_adj_state(adj->adj_state)); case ISIS_ISADJ_3WAYSTATE: return SNMP_INTEGER(adj->threeway_state); @@ -2538,27 +2555,7 @@ static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name, } case ISIS_ISADJ_NEIGHSYSTYPE: - - switch (adj->sys_type) { - case ISIS_SYSTYPE_UNKNOWN: - case ISIS_SYSTYPE_ES: - val = ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN; - break; - - case ISIS_SYSTYPE_IS: - val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1_L2; - break; - - case ISIS_SYSTYPE_L1_IS: - val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1; - break; - - case ISIS_SYSTYPE_L2_IS: - val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L2; - break; - } - - return SNMP_INTEGER(val); + return SNMP_INTEGER(isis_snmp_adj_neightype(adj->sys_type)); case ISIS_ISADJ_NEIGHSYSID: *var_len = sizeof(adj->sysid); @@ -3345,25 +3342,7 @@ static int isis_snmp_adj_state_change_update(const struct isis_adjacency *adj) lsp_id[ISIS_SYS_ID_LEN] = 0; lsp_id[ISIS_SYS_ID_LEN + 1] = 0; - val = ISIS_SNMP_ADJ_STATE_DOWN; - - switch (adj->adj_state) { - case ISIS_ADJ_UNKNOWN: - val = ISIS_SNMP_ADJ_STATE_DOWN; - break; - - case ISIS_ADJ_INITIALIZING: - val = ISIS_SNMP_ADJ_STATE_INITIALIZING; - break; - - case ISIS_ADJ_UP: - val = ISIS_SNMP_ADJ_STATE_UP; - break; - - case ISIS_ADJ_DOWN: - val = ISIS_SNMP_ADJ_STATE_FAILED; - break; - } + val = isis_snmp_adj_state(adj->adj_state); isis_snmp_update_worker_b( adj->circuit, ISIS_TRAP_ADJ_STATE_CHANGE, diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index c4024772f5..f7cef43d0d 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -361,9 +361,9 @@ struct sr_prefix_cfg *isis_sr_cfg_prefix_add(struct isis_area *area, pcfg->last_hop_behavior = yang_get_default_enum( "%s/prefix-sid-map/prefix-sid/last-hop-behavior", ISIS_SR); - /* Set the N-flag when appropriate. */ + /* Mark as node Sid if the prefix is host and configured in loopback */ ifp = if_lookup_prefix(prefix, VRF_DEFAULT); - if (ifp && sr_prefix_is_node_sid(ifp, prefix) && !pcfg->n_flag_clear) + if (ifp && sr_prefix_is_node_sid(ifp, prefix)) pcfg->node_sid = true; /* Save prefix-sid configuration. */ @@ -438,7 +438,7 @@ void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg, bool external, } if (external) SET_FLAG(psid->flags, ISIS_PREFIX_SID_READVERTISED); - if (pcfg->node_sid) + if (pcfg->node_sid && !pcfg->n_flag_clear) SET_FLAG(psid->flags, ISIS_PREFIX_SID_NODE); /* Set SID value. */ @@ -948,8 +948,7 @@ static int sr_if_new_hook(struct interface *ifp) if (!pcfg) continue; - if (sr_prefix_is_node_sid(ifp, &pcfg->prefix) - && !pcfg->n_flag_clear) { + if (sr_prefix_is_node_sid(ifp, &pcfg->prefix)) { pcfg->node_sid = true; lsp_regenerate_schedule(area, area->is_type, 0); } diff --git a/lib/northbound_db.c b/lib/northbound_db.c index 244e760b2b..dce9b2ec24 100644 --- a/lib/northbound_db.c +++ b/lib/northbound_db.c @@ -87,9 +87,12 @@ int nb_db_transaction_save(const struct nb_transaction *transaction, goto exit; client_name = nb_client_name(transaction->context->client); - /* Always record configurations in the XML format. */ + /* + * Always record configurations in the XML format, save the default + * values too, as this covers the case where defaults may change. + */ if (lyd_print_mem(&config_str, transaction->config->dnode, LYD_XML, - LYP_FORMAT | LYP_WITHSIBLINGS) + LYD_PRINT_WITHSIBLINGS | LYD_PRINT_WD_ALL) != 0) goto exit; @@ -149,6 +152,7 @@ struct nb_config *nb_db_transaction_load(uint32_t transaction_id) struct lyd_node *dnode; const char *config_str; struct sqlite3_stmt *ss; + LY_ERR err; ss = db_prepare( "SELECT\n" @@ -169,10 +173,11 @@ struct nb_config *nb_db_transaction_load(uint32_t transaction_id) if (db_loadf(ss, "%s", &config_str) != 0) goto exit; - dnode = lyd_parse_mem(ly_native_ctx, config_str, LYD_XML, - LYD_OPT_CONFIG); - if (!dnode) - flog_warn(EC_LIB_LIBYANG, "%s: lyd_parse_mem() failed", + err = lyd_parse_data_mem(ly_native_ctx, config_str, LYD_XML, + LYD_PARSE_STRICT | LYD_PARSE_NO_STATE, + LYD_VALIDATE_NO_STATE, &dnode); + if (err || !dnode) + flog_warn(EC_LIB_LIBYANG, "%s: lyd_parse_data_mem() failed", __func__); else config = nb_config_new(dnode); diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index dc2d29c11d..c61effdda5 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -199,9 +199,8 @@ class NorthboundImpl auto m = tag->response.add_supported_modules(); m->set_name(module->name); - if (module->info->rev_size) - m->set_revision( - module->info->rev[0].date); + if (module->info->revision) + m->set_revision(module->info->revision); m->set_organization(module->info->org); } @@ -1068,14 +1067,13 @@ class NorthboundImpl const std::string &path, const std::string &value) { - ly_errno = LY_SUCCESS; - dnode = lyd_new_path(dnode, ly_native_ctx, path.c_str(), - (void *)value.c_str(), - (LYD_ANYDATA_VALUETYPE)0, - LYD_PATH_OPT_UPDATE); - if (!dnode && ly_errno != LY_SUCCESS) { - flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed", - __func__); + LY_ERR err = lyd_new_path(dnode, ly_native_ctx, path.c_str(), + value.c_str(), LYD_NEW_PATH_UPDATE, + &dnode); + if (err != LY_SUCCESS) { + flog_warn(EC_LIB_LIBYANG, + "%s: lyd_new_path() failed: %s", __func__, + ly_errmsg(ly_native_ctx)); return -1; } @@ -1089,7 +1087,7 @@ class NorthboundImpl if (!dnode) return -1; - lyd_free(dnode); + lyd_free_tree(dnode); return 0; } @@ -1132,46 +1130,53 @@ class NorthboundImpl std::string(date), std::string(comment))); } - static int data_tree_from_dnode(frr::DataTree *dt, - const struct lyd_node *dnode, - LYD_FORMAT lyd_format, - bool with_defaults) + static LY_ERR data_tree_from_dnode(frr::DataTree *dt, + const struct lyd_node *dnode, + LYD_FORMAT lyd_format, + bool with_defaults) { char *strp; int options = 0; - SET_FLAG(options, LYP_FORMAT | LYP_WITHSIBLINGS); + SET_FLAG(options, LYD_PRINT_WITHSIBLINGS); if (with_defaults) - SET_FLAG(options, LYP_WD_ALL); + SET_FLAG(options, LYD_PRINT_WD_ALL); else - SET_FLAG(options, LYP_WD_TRIM); + SET_FLAG(options, LYD_PRINT_WD_TRIM); - if (lyd_print_mem(&strp, dnode, lyd_format, options) == 0) { + LY_ERR err = lyd_print_mem(&strp, dnode, lyd_format, options); + if (err == LY_SUCCESS) { if (strp) { dt->set_data(strp); free(strp); } - return 0; } - - return -1; + return err; } static struct lyd_node *dnode_from_data_tree(const frr::DataTree *dt, bool config_only) { struct lyd_node *dnode; - int options; - - if (config_only) - options = LYD_OPT_CONFIG; - else - options = LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB; - - dnode = lyd_parse_mem(ly_native_ctx, dt->data().c_str(), - encoding2lyd_format(dt->encoding()), - options); + int options, opt2; + LY_ERR err; + + if (config_only) { + options = LYD_PARSE_STRICT | LYD_PARSE_NO_STATE; + opt2 = LYD_VALIDATE_NO_STATE; + } else { + options = LYD_PARSE_STRICT; + opt2 = 0; + } + err = lyd_parse_data_mem(ly_native_ctx, dt->data().c_str(), + encoding2lyd_format(dt->encoding()), + options, opt2, &dnode); + if (err != LY_SUCCESS) { + flog_warn(EC_LIB_LIBYANG, + "%s: lyd_parse_mem() failed: %s", __func__, + ly_errmsg(ly_native_ctx)); + } return dnode; } @@ -1239,14 +1244,15 @@ class NorthboundImpl // Combine configuration and state data into a single // dnode. // - if (lyd_merge(dnode_state, dnode_config, - LYD_OPT_EXPLICIT) - != 0) { + if (lyd_merge_tree(&dnode_state, dnode_config, + LYD_MERGE_DESTRUCT) + != LY_SUCCESS) { yang_dnode_free(dnode_state); yang_dnode_free(dnode_config); return grpc::Status( grpc::StatusCode::INTERNAL, - "Failed to merge configuration and state data"); + "Failed to merge configuration and state data", + ly_errmsg(ly_native_ctx)); } dnode_final = dnode_state; @@ -1262,19 +1268,25 @@ class NorthboundImpl // Validate data to create implicit default nodes if necessary. int validate_opts = 0; if (type == frr::GetRequest_DataType_CONFIG) - validate_opts = LYD_OPT_CONFIG; + validate_opts = LYD_VALIDATE_NO_STATE; else - validate_opts = LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB; - lyd_validate(&dnode_final, validate_opts, ly_native_ctx); + validate_opts = 0; + LY_ERR err = lyd_validate_all(&dnode_final, ly_native_ctx, + validate_opts, NULL); + + if (err) + flog_warn(EC_LIB_LIBYANG, + "%s: lyd_validate_all() failed: %s", __func__, + ly_errmsg(ly_native_ctx)); // Dump data using the requested format. - int ret = data_tree_from_dnode(dt, dnode_final, lyd_format, - with_defaults); + if (!err) + err = data_tree_from_dnode(dt, dnode_final, lyd_format, + with_defaults); yang_dnode_free(dnode_final); - if (ret != 0) + if (err) return grpc::Status(grpc::StatusCode::INTERNAL, "Failed to dump data"); - return grpc::Status::OK; } diff --git a/lib/xref.h b/lib/xref.h index 949458b313..6cff1a3769 100644 --- a/lib/xref.h +++ b/lib/xref.h @@ -169,6 +169,7 @@ extern const struct xref * const __stop_xref_array[1] DSO_LOCAL; static void __attribute__((used, _CONSTRUCTOR(1100))) \ _xref_init(void) { \ static struct xref_block _xref_block = { \ + .next = NULL, \ .start = __start_xref_array, \ .stop = __stop_xref_array, \ }; \ diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index a5c188c465..2376409ccd 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -156,6 +156,16 @@ static void ospf6_set_redist_vrf_bitmaps(struct ospf6 *ospf6, bool set) vrf_bitmap_unset(zclient->redist[AFI_IP6][type], ospf6->vrf_id); } + + red_list = ospf6->redist[DEFAULT_ROUTE]; + if (red_list) { + if (set) + vrf_bitmap_set(zclient->default_information[AFI_IP6], + ospf6->vrf_id); + else + vrf_bitmap_unset(zclient->default_information[AFI_IP6], + ospf6->vrf_id); + } } /* Disable OSPF6 VRF instance */ diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index 7e7236a3b6..81de882754 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -58,7 +58,7 @@ /* For debugging only, will be removed */ -void api_opaque_lsa_print(struct lsa_header *data) +void api_opaque_lsa_print(struct ospf_lsa *lsa) { struct opaque_lsa { struct lsa_header header; @@ -69,11 +69,11 @@ void api_opaque_lsa_print(struct lsa_header *data) int opaquelen; int i; - ospf_lsa_header_dump(data); + ospf_lsa_header_dump(lsa->data); - olsa = (struct opaque_lsa *)data; + olsa = (struct opaque_lsa *)lsa->data; - opaquelen = ntohs(data->length) - OSPF_LSA_HEADER_SIZE; + opaquelen = lsa->size - OSPF_LSA_HEADER_SIZE; zlog_debug("apiserver_lsa_print: opaquelen=%d", opaquelen); for (i = 0; i < opaquelen; i++) { @@ -111,11 +111,16 @@ struct msg *msg_new(uint8_t msgtype, void *msgbody, uint32_t seqnum, struct msg *msg_dup(struct msg *msg) { struct msg *new; + size_t size; assert(msg); + size = ntohs(msg->hdr.msglen); + if (size > OSPF_MAX_LSA_SIZE) + return NULL; + new = msg_new(msg->hdr.msgtype, STREAM_DATA(msg->s), - ntohl(msg->hdr.msgseq), ntohs(msg->hdr.msglen)); + ntohl(msg->hdr.msgseq), size); return new; } @@ -400,7 +405,7 @@ struct msg *msg_read(int fd) } /* Allocate new message */ - msg = msg_new(hdr.msgtype, buf, ntohl(hdr.msgseq), ntohs(hdr.msglen)); + msg = msg_new(hdr.msgtype, buf, ntohl(hdr.msgseq), bodylen); return msg; } @@ -408,29 +413,34 @@ struct msg *msg_read(int fd) int msg_write(int fd, struct msg *msg) { uint8_t buf[OSPF_API_MAX_MSG_SIZE]; - int l; + uint16_t l; int wlen; assert(msg); assert(msg->s); - /* Length of message including header */ - l = sizeof(struct apimsghdr) + ntohs(msg->hdr.msglen); + /* Length of OSPF LSA payload */ + l = ntohs(msg->hdr.msglen); + if (l > OSPF_MAX_LSA_SIZE) { + zlog_warn("%s: wrong LSA size %d", __func__, l); + return -1; + } /* Make contiguous memory buffer for message */ memcpy(buf, &msg->hdr, sizeof(struct apimsghdr)); - memcpy(buf + sizeof(struct apimsghdr), STREAM_DATA(msg->s), - ntohs(msg->hdr.msglen)); + memcpy(buf + sizeof(struct apimsghdr), STREAM_DATA(msg->s), l); + /* Total length of OSPF API Message */ + l += sizeof(struct apimsghdr); wlen = writen(fd, buf, l); if (wlen < 0) { - zlog_warn("msg_write: writen %s", safe_strerror(errno)); + zlog_warn("%s: writen %s", __func__, safe_strerror(errno)); return -1; } else if (wlen == 0) { - zlog_warn("msg_write: Connection closed by peer"); + zlog_warn("%s: Connection closed by peer", __func__); return -1; } else if (wlen != l) { - zlog_warn("msg_write: Cannot write API message"); + zlog_warn("%s: Cannot write API message", __func__); return -1; } return 0; diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h index 0fc683a5db..c20284aed5 100644 --- a/ospfd/ospf_api.h +++ b/ospfd/ospf_api.h @@ -276,7 +276,7 @@ struct apimsg { */ /* For debugging only. */ -extern void api_opaque_lsa_print(struct lsa_header *data); +extern void api_opaque_lsa_print(struct ospf_lsa *lsa); /* Messages sent by client */ extern struct msg *new_msg_register_opaque_type(uint32_t seqnum, uint8_t ltype, diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index c01ecdd1d4..cbd03441ef 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -1156,6 +1156,7 @@ int ospf_apiserver_handle_register_event(struct ospf_apiserver *apiserv, struct msg_register_event *rmsg; int rc; uint32_t seqnum; + size_t size; rmsg = (struct msg_register_event *)STREAM_DATA(msg->s); @@ -1165,13 +1166,16 @@ int ospf_apiserver_handle_register_event(struct ospf_apiserver *apiserv, /* Free existing filter in apiserv. */ XFREE(MTYPE_OSPF_APISERVER_MSGFILTER, apiserv->filter); /* Alloc new space for filter. */ + size = ntohs(msg->hdr.msglen); + if (size < OSPF_MAX_LSA_SIZE) { - apiserv->filter = - XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER, ntohs(msg->hdr.msglen)); + apiserv->filter = XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER, size); - /* copy it over. */ - memcpy(apiserv->filter, &rmsg->filter, ntohs(msg->hdr.msglen)); - rc = OSPF_API_OK; + /* copy it over. */ + memcpy(apiserv->filter, &rmsg->filter, size); + rc = OSPF_API_OK; + } else + rc = OSPF_API_NOMEMORY; /* Send a reply back to client with return code */ rc = ospf_apiserver_send_reply(apiserv, seqnum, rc); diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 8f31f90346..e490070d03 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -241,7 +241,7 @@ const char *ospf_timer_dump(struct thread *t, char *buf, size_t size) static void ospf_packet_hello_dump(struct stream *s, uint16_t length) { struct ospf_hello *hello; - int i; + int i, len; hello = (struct ospf_hello *)stream_pnt(s); @@ -256,9 +256,9 @@ static void ospf_packet_hello_dump(struct stream *s, uint16_t length) zlog_debug(" DRouter %pI4", &hello->d_router); zlog_debug(" BDRouter %pI4", &hello->bd_router); - length -= OSPF_HEADER_SIZE + OSPF_HELLO_MIN_SIZE; - zlog_debug(" # Neighbors %d", length / 4); - for (i = 0; length > 0; i++, length -= sizeof(struct in_addr)) + len = length - OSPF_HEADER_SIZE - OSPF_HELLO_MIN_SIZE; + zlog_debug(" # Neighbors %d", len / 4); + for (i = 0; len > 0; i++, len -= sizeof(struct in_addr)) zlog_debug(" Neighbor %pI4", &hello->neighbors[i]); } @@ -285,7 +285,8 @@ static void ospf_router_lsa_dump(struct stream *s, uint16_t length) { char buf[BUFSIZ]; struct router_lsa *rl; - int i, len; + struct router_link *rlnk; + int i, len, sum; rl = (struct router_lsa *)stream_pnt(s); @@ -294,16 +295,15 @@ static void ospf_router_lsa_dump(struct stream *s, uint16_t length) ospf_router_lsa_flags_dump(rl->flags, buf, BUFSIZ)); zlog_debug(" # links %d", ntohs(rl->links)); - len = ntohs(rl->header.length) - OSPF_LSA_HEADER_SIZE - 4; - for (i = 0; len > 0; i++) { - zlog_debug(" Link ID %pI4", &rl->link[i].link_id); - zlog_debug(" Link Data %pI4", - &rl->link[i].link_data); - zlog_debug(" Type %d", (uint8_t)rl->link[i].type); - zlog_debug(" TOS %d", (uint8_t)rl->link[i].tos); - zlog_debug(" metric %d", ntohs(rl->link[i].metric)); - - len -= 12; + len = length - OSPF_LSA_HEADER_SIZE - 4; + rlnk = &rl->link[0]; + sum = 0; + for (i = 0; sum < len && rlnk; sum += 12, rlnk = &rl->link[++i]) { + zlog_debug(" Link ID %pI4", &rlnk->link_id); + zlog_debug(" Link Data %pI4", &rlnk->link_data); + zlog_debug(" Type %d", (uint8_t)rlnk->type); + zlog_debug(" TOS %d", (uint8_t)rlnk->tos); + zlog_debug(" metric %d", ntohs(rlnk->metric)); } } @@ -312,10 +312,11 @@ static void ospf_network_lsa_dump(struct stream *s, uint16_t length) struct network_lsa *nl; int i, cnt; + zlog_debug(" Network-LSA"); + nl = (struct network_lsa *)stream_pnt(s); - cnt = (ntohs(nl->header.length) - (OSPF_LSA_HEADER_SIZE + 4)) / 4; + cnt = (length - (OSPF_LSA_HEADER_SIZE + 4)) / 4; - zlog_debug(" Network-LSA"); /* zlog_debug ("LSA total size %d", ntohs (nl->header.length)); zlog_debug ("Network-LSA size %d", @@ -331,55 +332,53 @@ static void ospf_network_lsa_dump(struct stream *s, uint16_t length) static void ospf_summary_lsa_dump(struct stream *s, uint16_t length) { struct summary_lsa *sl; - int size; - int i; sl = (struct summary_lsa *)stream_pnt(s); zlog_debug(" Summary-LSA"); zlog_debug(" Network Mask %pI4", &sl->mask); - - size = ntohs(sl->header.length) - OSPF_LSA_HEADER_SIZE - 4; - for (i = 0; size > 0; size -= 4, i++) - zlog_debug(" TOS=%d metric %d", sl->tos, - GET_METRIC(sl->metric)); + zlog_debug(" TOS=%d metric %d", sl->tos, GET_METRIC(sl->metric)); } static void ospf_as_external_lsa_dump(struct stream *s, uint16_t length) { struct as_external_lsa *al; - int size; + struct as_route *asr; + int size, sum; int i; al = (struct as_external_lsa *)stream_pnt(s); zlog_debug(" %s", ospf_lsa_type_msg[al->header.type].str); zlog_debug(" Network Mask %pI4", &al->mask); - size = ntohs(al->header.length) - OSPF_LSA_HEADER_SIZE - 4; - for (i = 0; size > 0; size -= 12, i++) { + size = length - OSPF_LSA_HEADER_SIZE - 4; + asr = &al->e[0]; + sum = 0; + for (i = 0; sum < size && asr; sum += 12, asr = &al->e[++i]) { zlog_debug(" bit %s TOS=%d metric %d", - IS_EXTERNAL_METRIC(al->e[i].tos) ? "E" : "-", - al->e[i].tos & 0x7f, GET_METRIC(al->e[i].metric)); - zlog_debug(" Forwarding address %pI4", - &al->e[i].fwd_addr); + IS_EXTERNAL_METRIC(asr->tos) ? "E" : "-", + asr->tos & 0x7f, GET_METRIC(asr->metric)); + zlog_debug(" Forwarding address %pI4", &asr->fwd_addr); zlog_debug(" External Route Tag %" ROUTE_TAG_PRI, - al->e[i].route_tag); + asr->route_tag); } } static void ospf_lsa_header_list_dump(struct stream *s, uint16_t length) { struct lsa_header *lsa; + int len; zlog_debug(" # LSA Headers %d", length / OSPF_LSA_HEADER_SIZE); /* LSA Headers. */ - while (length > 0) { + len = length; + while (len > 0) { lsa = (struct lsa_header *)stream_pnt(s); ospf_lsa_header_dump(lsa); stream_forward_getp(s, OSPF_LSA_HEADER_SIZE); - length -= OSPF_LSA_HEADER_SIZE; + len -= OSPF_LSA_HEADER_SIZE; } } @@ -417,6 +416,7 @@ static void ospf_packet_ls_req_dump(struct stream *s, uint16_t length) uint32_t ls_type; struct in_addr ls_id; struct in_addr adv_router; + int sum; sp = stream_get_getp(s); @@ -425,7 +425,8 @@ static void ospf_packet_ls_req_dump(struct stream *s, uint16_t length) zlog_debug("Link State Request"); zlog_debug(" # Requests %d", length / 12); - for (; length > 0; length -= 12) { + sum = 0; + for (; sum < length; sum += 12) { ls_type = stream_getl(s); ls_id.s_addr = stream_get_ipv4(s); adv_router.s_addr = stream_get_ipv4(s); @@ -442,23 +443,23 @@ static void ospf_packet_ls_upd_dump(struct stream *s, uint16_t length) { uint32_t sp; struct lsa_header *lsa; - int lsa_len; + int lsa_len, len; uint32_t count; - length -= OSPF_HEADER_SIZE; + len = length - OSPF_HEADER_SIZE; sp = stream_get_getp(s); count = stream_getl(s); - length -= 4; + len -= 4; zlog_debug("Link State Update"); zlog_debug(" # LSAs %d", count); - while (length > 0 && count > 0) { - if (length < OSPF_HEADER_SIZE || length % 4 != 0) { + while (len > 0 && count > 0) { + if ((uint16_t)len < OSPF_LSA_HEADER_SIZE || len % 4 != 0) { zlog_debug(" Remaining %d bytes; Incorrect length.", - length); + len); break; } @@ -466,34 +467,39 @@ static void ospf_packet_ls_upd_dump(struct stream *s, uint16_t length) lsa_len = ntohs(lsa->length); ospf_lsa_header_dump(lsa); + /* Check that LSA length is valid */ + if (lsa_len > len || lsa_len % 4 != 0) { + zlog_debug(" LSA length %d is incorrect!", lsa_len); + break; + } switch (lsa->type) { case OSPF_ROUTER_LSA: - ospf_router_lsa_dump(s, length); + ospf_router_lsa_dump(s, lsa_len); break; case OSPF_NETWORK_LSA: - ospf_network_lsa_dump(s, length); + ospf_network_lsa_dump(s, lsa_len); break; case OSPF_SUMMARY_LSA: case OSPF_ASBR_SUMMARY_LSA: - ospf_summary_lsa_dump(s, length); + ospf_summary_lsa_dump(s, lsa_len); break; case OSPF_AS_EXTERNAL_LSA: - ospf_as_external_lsa_dump(s, length); + ospf_as_external_lsa_dump(s, lsa_len); break; case OSPF_AS_NSSA_LSA: - ospf_as_external_lsa_dump(s, length); + ospf_as_external_lsa_dump(s, lsa_len); break; case OSPF_OPAQUE_LINK_LSA: case OSPF_OPAQUE_AREA_LSA: case OSPF_OPAQUE_AS_LSA: - ospf_opaque_lsa_dump(s, length); + ospf_opaque_lsa_dump(s, lsa_len); break; default: break; } stream_forward_getp(s, lsa_len); - length -= lsa_len; + len -= lsa_len; count--; } diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c index 754e2bcbab..2d08eeece2 100644 --- a/ospfd/ospf_ext.c +++ b/ospfd/ospf_ext.c @@ -1715,13 +1715,23 @@ static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op) * ------------------------------------ */ +#define check_tlv_size(size, msg) \ + do { \ + if (ntohs(tlvh->length) != size) { \ + vty_out(vty, " Wrong %s TLV size: %d(%d). Abort!\n", \ + msg, ntohs(tlvh->length), size); \ + return size + TLV_HDR_SIZE; \ + } \ + } while (0) + /* Cisco experimental SubTLV */ static uint16_t show_vty_ext_link_rmt_itf_addr(struct vty *vty, struct tlv_header *tlvh) { - struct ext_subtlv_rmt_itf_addr *top; + struct ext_subtlv_rmt_itf_addr *top = + (struct ext_subtlv_rmt_itf_addr *)tlvh; - top = (struct ext_subtlv_rmt_itf_addr *)tlvh; + check_tlv_size(EXT_SUBTLV_RMT_ITF_ADDR_SIZE, "Remote Itf. Address"); vty_out(vty, " Remote Interface Address Sub-TLV: Length %u\n Address: %pI4\n", @@ -1736,6 +1746,8 @@ static uint16_t show_vty_ext_link_adj_sid(struct vty *vty, { struct ext_subtlv_adj_sid *top = (struct ext_subtlv_adj_sid *)tlvh; + check_tlv_size(EXT_SUBTLV_ADJ_SID_SIZE, "Adjacency SID"); + vty_out(vty, " Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n", ntohs(top->header.length), top->flags, top->mtid, top->weight, @@ -1755,6 +1767,8 @@ static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty, struct ext_subtlv_lan_adj_sid *top = (struct ext_subtlv_lan_adj_sid *)tlvh; + check_tlv_size(EXT_SUBTLV_LAN_ADJ_SID_SIZE, "Lan-Adjacency SID"); + vty_out(vty, " LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: %pI4\n\t%s: %u\n", ntohs(top->header.length), top->flags, top->mtid, top->weight, @@ -1768,8 +1782,15 @@ static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty, return TLV_SIZE(tlvh); } -static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh) +static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, + size_t buf_size) { + if (TLV_SIZE(tlvh) > buf_size) { + vty_out(vty, " TLV size %d exceeds buffer size. Abort!", + TLV_SIZE(tlvh)); + return buf_size; + } + vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", ntohs(tlvh->type), ntohs(tlvh->length)); @@ -1777,13 +1798,22 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh) } /* Extended Link Sub TLVs */ -static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext) +static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext, + size_t buf_size) { struct ext_tlv_link *top = (struct ext_tlv_link *)ext; struct tlv_header *tlvh; - uint16_t length = ntohs(top->header.length) - 3 * sizeof(uint32_t); + uint16_t length = ntohs(top->header.length); uint16_t sum = 0; + /* Verify that TLV length is valid against remaining buffer size */ + if (length > buf_size) { + vty_out(vty, + " Extended Link TLV size %d exceeds buffer size. Abort!\n", + length); + return buf_size; + } + vty_out(vty, " Extended Link TLV: Length %u\n Link Type: 0x%x\n" " Link ID: %pI4\n", @@ -1791,9 +1821,11 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext) &top->link_id); vty_out(vty, " Link data: %pI4\n", &top->link_data); + /* Skip Extended TLV and parse sub-TLVs */ + length -= EXT_TLV_LINK_SIZE; tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE + EXT_TLV_LINK_SIZE); - for (; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) { + for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case EXT_SUBTLV_ADJ_SID: sum += show_vty_ext_link_adj_sid(vty, tlvh); @@ -1805,7 +1837,7 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext) sum += show_vty_ext_link_rmt_itf_addr(vty, tlvh); break; default: - sum += show_vty_unknown_tlv(vty, tlvh); + sum += show_vty_unknown_tlv(vty, tlvh, length - sum); break; } } @@ -1821,16 +1853,16 @@ static void ospf_ext_link_show_info(struct vty *vty, struct ospf_lsa *lsa) uint16_t length = 0, sum = 0; /* Initialize TLV browsing */ - length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; + length = lsa->size - OSPF_LSA_HEADER_SIZE; - for (tlvh = TLV_HDR_TOP(lsah); sum < length; + for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case EXT_TLV_LINK: - sum += show_vty_link_info(vty, tlvh); + sum += show_vty_link_info(vty, tlvh, length - sum); break; default: - sum += show_vty_unknown_tlv(vty, tlvh); + sum += show_vty_unknown_tlv(vty, tlvh, length - sum); break; } } @@ -1843,6 +1875,8 @@ static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty, struct ext_subtlv_prefix_sid *top = (struct ext_subtlv_prefix_sid *)tlvh; + check_tlv_size(EXT_SUBTLV_PREFIX_SID_SIZE, "Prefix SID"); + vty_out(vty, " Prefix SID Sub-TLV: Length %u\n\tAlgorithm: %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n", ntohs(top->header.length), top->algorithm, top->flags, @@ -1857,28 +1891,39 @@ static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty, } /* Extended Prefix SubTLVs */ -static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext) +static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext, + size_t buf_size) { struct ext_tlv_prefix *top = (struct ext_tlv_prefix *)ext; struct tlv_header *tlvh; - uint16_t length = ntohs(top->header.length) - 2 * sizeof(uint32_t); + uint16_t length = ntohs(top->header.length); uint16_t sum = 0; + /* Verify that TLV length is valid against remaining buffer size */ + if (length > buf_size) { + vty_out(vty, + " Extended Link TLV size %d exceeds buffer size. Abort!\n", + length); + return buf_size; + } + vty_out(vty, " Extended Prefix TLV: Length %u\n\tRoute Type: %u\n" "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %pI4/%u\n", ntohs(top->header.length), top->route_type, top->af, top->flags, &top->address, top->pref_length); + /* Skip Extended Prefix TLV and parse sub-TLVs */ + length -= EXT_TLV_PREFIX_SIZE; tlvh = (struct tlv_header *)((char *)(ext) + TLV_HDR_SIZE + EXT_TLV_PREFIX_SIZE); - for (; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) { + for (; sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case EXT_SUBTLV_PREFIX_SID: sum += show_vty_ext_pref_pref_sid(vty, tlvh); break; default: - sum += show_vty_unknown_tlv(vty, tlvh); + sum += show_vty_unknown_tlv(vty, tlvh, length - sum); break; } } @@ -1894,16 +1939,16 @@ static void ospf_ext_pref_show_info(struct vty *vty, struct ospf_lsa *lsa) uint16_t length = 0, sum = 0; /* Initialize TLV browsing */ - length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; + length = lsa->size - OSPF_LSA_HEADER_SIZE; - for (tlvh = TLV_HDR_TOP(lsah); sum < length; + for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case EXT_TLV_PREFIX: - sum += show_vty_pref_info(vty, tlvh); + sum += show_vty_pref_info(vty, tlvh, length - sum); break; default: - sum += show_vty_unknown_tlv(vty, tlvh); + sum += show_vty_unknown_tlv(vty, tlvh, length - sum); break; } } diff --git a/ospfd/ospf_gr_helper.c b/ospfd/ospf_gr_helper.c index d818878cf5..a25057a27f 100644 --- a/ospfd/ospf_gr_helper.c +++ b/ospfd/ospf_gr_helper.c @@ -233,19 +233,17 @@ static int ospf_extract_grace_lsa_fields(struct ospf_lsa *lsa, lsah = (struct lsa_header *)lsa->data; - length = ntohs(lsah->length); - /* Check LSA len */ - if (length <= OSPF_LSA_HEADER_SIZE) { + if (lsa->size <= OSPF_LSA_HEADER_SIZE) { if (IS_DEBUG_OSPF_GR_HELPER) zlog_debug("%s: Malformed packet: Invalid LSA len:%d", __func__, length); return OSPF_GR_FAILURE; } - length -= OSPF_LSA_HEADER_SIZE; + length = lsa->size - OSPF_LSA_HEADER_SIZE; - for (tlvh = TLV_HDR_TOP(lsah); sum < length; + for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { /* Check TLV len against overall LSA */ @@ -996,18 +994,16 @@ static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa) lsah = (struct lsa_header *)lsa->data; - length = ntohs(lsah->length); - - if (length <= OSPF_LSA_HEADER_SIZE) { + if (lsa->size <= OSPF_LSA_HEADER_SIZE) { vty_out(vty, "%% Invalid LSA length: %d\n", length); return; } - length -= OSPF_LSA_HEADER_SIZE; + length = lsa->size - OSPF_LSA_HEADER_SIZE; vty_out(vty, " TLV info:\n"); - for (tlvh = TLV_HDR_TOP(lsah); sum < length; + for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { /* Check TLV len */ if (sum + TLV_SIZE(tlvh) > length) { diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index 6e9df77fb8..72dc699bd9 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -175,6 +175,7 @@ struct ospf_lsa *ospf_lsa_new_and_data(size_t size) new = ospf_lsa_new(); new->data = ospf_lsa_data_new(size); + new->size = size; return new; } @@ -3241,22 +3242,22 @@ int ospf_lsa_different(struct ospf_lsa *l1, struct ospf_lsa *l2) if (IS_LSA_MAXAGE(l2) && !IS_LSA_MAXAGE(l1)) return 1; - if (l1->data->length != l2->data->length) + if (l1->size != l2->size) return 1; - if (l1->data->length == 0) + if (l1->size == 0) return 1; if (CHECK_FLAG((l1->flags ^ l2->flags), OSPF_LSA_RECEIVED)) return 1; /* May be a stale LSA in the LSBD */ - assert(ntohs(l1->data->length) > OSPF_LSA_HEADER_SIZE); + assert(l1->size > OSPF_LSA_HEADER_SIZE); p1 = (char *)l1->data; p2 = (char *)l2->data; if (memcmp(p1 + OSPF_LSA_HEADER_SIZE, p2 + OSPF_LSA_HEADER_SIZE, - ntohs(l1->data->length) - OSPF_LSA_HEADER_SIZE) + l1->size - OSPF_LSA_HEADER_SIZE) != 0) return 1; diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 3c1f94e628..3808700ccc 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -84,8 +84,9 @@ struct ospf_lsa { #define OSPF_LSA_PREMATURE_AGE 0x40 #define OSPF_LSA_IN_MAXAGE 0x80 - /* LSA data. */ + /* LSA data. and size */ struct lsa_header *data; + size_t size; /* Received time stamp. */ struct timeval tv_recv; @@ -168,7 +169,7 @@ struct router_lsa { uint8_t flags; uint8_t zero; uint16_t links; - struct { + struct router_link { struct in_addr link_id; struct in_addr link_data; uint8_t type; @@ -199,7 +200,7 @@ struct summary_lsa { struct as_external_lsa { struct lsa_header header; struct in_addr mask; - struct { + struct as_route { uint8_t tos; uint8_t metric[3]; struct in_addr fwd_addr; diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index ae9ab48d4a..42bf914f67 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -1204,9 +1204,10 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa, void ospf_opaque_lsa_dump(struct stream *s, uint16_t length) { - struct ospf_lsa lsa; + struct ospf_lsa lsa = {}; lsa.data = (struct lsa_header *)stream_pnt(s); + lsa.size = length; show_opaque_info_detail(NULL, &lsa, NULL); return; } diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h index c63b8ebdaf..7d401c3dcc 100644 --- a/ospfd/ospf_opaque.h +++ b/ospfd/ospf_opaque.h @@ -79,6 +79,7 @@ #define VALID_OPAQUE_INFO_LEN(lsahdr) \ ((ntohs((lsahdr)->length) >= sizeof(struct lsa_header)) \ + && ((ntohs((lsahdr)->length) < OSPF_MAX_LSA_SIZE)) \ && ((ntohs((lsahdr)->length) % sizeof(uint32_t)) == 0)) /* diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 988bcd67c6..4b77943108 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -294,8 +294,8 @@ static void set_pce_address(struct in_addr ipv4, struct ospf_pce_info *pce) pce->pce_header.header.type = htons(RI_TLV_PCE); /* Set PCE Address */ pce->pce_address.header.type = htons(RI_PCE_SUBTLV_ADDRESS); - pce->pce_address.header.length = htons(PCE_ADDRESS_LENGTH_IPV4); - pce->pce_address.address.type = htons(PCE_ADDRESS_TYPE_IPV4); + pce->pce_address.header.length = htons(PCE_ADDRESS_IPV4_SIZE); + pce->pce_address.address.type = htons(PCE_ADDRESS_IPV4); pce->pce_address.address.value = ipv4; return; @@ -323,7 +323,7 @@ static void set_pce_domain(uint16_t type, uint32_t domain, sizeof(struct ri_pce_subtlv_domain)); new->header.type = htons(RI_PCE_SUBTLV_DOMAIN); - new->header.length = htons(PCE_ADDRESS_LENGTH_IPV4); + new->header.length = htons(PCE_ADDRESS_IPV4_SIZE); new->type = htons(type); new->value = htonl(domain); @@ -369,7 +369,7 @@ static void set_pce_neighbor(uint16_t type, uint32_t domain, sizeof(struct ri_pce_subtlv_neighbor)); new->header.type = htons(RI_PCE_SUBTLV_NEIGHBOR); - new->header.length = htons(PCE_ADDRESS_LENGTH_IPV4); + new->header.length = htons(PCE_ADDRESS_IPV4_SIZE); new->type = htons(type); new->value = htonl(domain); @@ -1224,10 +1224,25 @@ static int ospf_router_info_lsa_update(struct ospf_lsa *lsa) * Followings are vty session control functions. *------------------------------------------------------------------------*/ +#define check_tlv_size(size, msg) \ + do { \ + if (ntohs(tlvh->length) > size) { \ + if (vty != NULL) \ + vty_out(vty, " Wrong %s TLV size: %d(%d)\n", \ + msg, ntohs(tlvh->length), size); \ + else \ + zlog_debug(" Wrong %s TLV size: %d(%d)\n", \ + msg, ntohs(tlvh->length), size); \ + return size + TLV_HDR_SIZE; \ + } \ + } while (0) + static uint16_t show_vty_router_cap(struct vty *vty, struct tlv_header *tlvh) { struct ri_tlv_router_cap *top = (struct ri_tlv_router_cap *)tlvh; + check_tlv_size(RI_TLV_CAPABILITIES_SIZE, "Router Capabilities"); + if (vty != NULL) vty_out(vty, " Router Capabilities: 0x%x\n", ntohl(top->value)); @@ -1243,21 +1258,30 @@ static uint16_t show_vty_pce_subtlv_address(struct vty *vty, struct ri_pce_subtlv_address *top = (struct ri_pce_subtlv_address *)tlvh; - if (ntohs(top->address.type) == PCE_ADDRESS_TYPE_IPV4) { + if (ntohs(top->address.type) == PCE_ADDRESS_IPV4) { + check_tlv_size(PCE_ADDRESS_IPV4_SIZE, "PCE Address"); if (vty != NULL) vty_out(vty, " PCE Address: %pI4\n", &top->address.value); else zlog_debug(" PCE Address: %pI4", &top->address.value); - } else { + } else if (ntohs(top->address.type) == PCE_ADDRESS_IPV6) { /* TODO: Add support to IPv6 with inet_ntop() */ + check_tlv_size(PCE_ADDRESS_IPV6_SIZE, "PCE Address"); if (vty != NULL) vty_out(vty, " PCE Address: 0x%x\n", ntohl(top->address.value.s_addr)); else zlog_debug(" PCE Address: 0x%x", ntohl(top->address.value.s_addr)); + } else { + if (vty != NULL) + vty_out(vty, " Wrong PCE Address type: 0x%x\n", + ntohl(top->address.type)); + else + zlog_debug(" Wrong PCE Address type: 0x%x", + ntohl(top->address.type)); } return TLV_SIZE(tlvh); @@ -1269,6 +1293,8 @@ static uint16_t show_vty_pce_subtlv_path_scope(struct vty *vty, struct ri_pce_subtlv_path_scope *top = (struct ri_pce_subtlv_path_scope *)tlvh; + check_tlv_size(RI_PCE_SUBTLV_PATH_SCOPE_SIZE, "PCE Path Scope"); + if (vty != NULL) vty_out(vty, " PCE Path Scope: 0x%x\n", ntohl(top->value)); else @@ -1283,19 +1309,29 @@ static uint16_t show_vty_pce_subtlv_domain(struct vty *vty, struct ri_pce_subtlv_domain *top = (struct ri_pce_subtlv_domain *)tlvh; struct in_addr tmp; + check_tlv_size(RI_PCE_SUBTLV_DOMAIN_SIZE, "PCE Domain"); + if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) { tmp.s_addr = top->value; if (vty != NULL) - vty_out(vty, " PCE domain Area: %pI4\n", &tmp); + vty_out(vty, " PCE Domain Area: %pI4\n", &tmp); else - zlog_debug(" PCE domain Area: %pI4", &tmp); - } else { + zlog_debug(" PCE Domain Area: %pI4", &tmp); + } else if (ntohs(top->type) == PCE_DOMAIN_TYPE_AS) { if (vty != NULL) - vty_out(vty, " PCE domain AS: %d\n", + vty_out(vty, " PCE Domain AS: %d\n", ntohl(top->value)); else - zlog_debug(" PCE domain AS: %d", ntohl(top->value)); + zlog_debug(" PCE Domain AS: %d", ntohl(top->value)); + } else { + if (vty != NULL) + vty_out(vty, " Wrong PCE Domain type: %d\n", + ntohl(top->type)); + else + zlog_debug(" Wrong PCE Domain type: %d", + ntohl(top->type)); } + return TLV_SIZE(tlvh); } @@ -1307,21 +1343,30 @@ static uint16_t show_vty_pce_subtlv_neighbor(struct vty *vty, (struct ri_pce_subtlv_neighbor *)tlvh; struct in_addr tmp; + check_tlv_size(RI_PCE_SUBTLV_NEIGHBOR_SIZE, "PCE Neighbor"); + if (ntohs(top->type) == PCE_DOMAIN_TYPE_AREA) { tmp.s_addr = top->value; if (vty != NULL) - vty_out(vty, " PCE neighbor Area: %pI4\n", - &tmp); + vty_out(vty, " PCE Neighbor Area: %pI4\n", &tmp); else - zlog_debug(" PCE neighbor Area: %pI4", &tmp); - } else { + zlog_debug(" PCE Neighbor Area: %pI4", &tmp); + } else if (ntohs(top->type) == PCE_DOMAIN_TYPE_AS) { if (vty != NULL) - vty_out(vty, " PCE neighbor AS: %d\n", + vty_out(vty, " PCE Neighbor AS: %d\n", ntohl(top->value)); else - zlog_debug(" PCE neighbor AS: %d", + zlog_debug(" PCE Neighbor AS: %d", ntohl(top->value)); + } else { + if (vty != NULL) + vty_out(vty, " Wrong PCE Neighbor type: %d\n", + ntohl(top->type)); + else + zlog_debug(" Wrong PCE Neighbor type: %d", + ntohl(top->type)); } + return TLV_SIZE(tlvh); } @@ -1331,6 +1376,8 @@ static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty, struct ri_pce_subtlv_cap_flag *top = (struct ri_pce_subtlv_cap_flag *)tlvh; + check_tlv_size(RI_PCE_SUBTLV_CAP_FLAG_SIZE, "PCE Capabilities"); + if (vty != NULL) vty_out(vty, " PCE Capabilities Flag: 0x%x\n", ntohl(top->value)); @@ -1341,8 +1388,21 @@ static uint16_t show_vty_pce_subtlv_cap_flag(struct vty *vty, return TLV_SIZE(tlvh); } -static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh) +static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, + size_t buf_size) { + if (TLV_SIZE(tlvh) > buf_size) { + if (vty != NULL) + vty_out(vty, + " TLV size %d exceeds buffer size. Abort!", + TLV_SIZE(tlvh)); + else + zlog_debug( + " TLV size %d exceeds buffer size. Abort!", + TLV_SIZE(tlvh)); + return buf_size; + } + if (vty != NULL) vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", ntohs(tlvh->type), ntohs(tlvh->length)); @@ -1354,12 +1414,21 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh) } static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri, - uint32_t total) + size_t buf_size) { struct tlv_header *tlvh; + uint16_t length = ntohs(ri->length); uint16_t sum = 0; - for (tlvh = ri; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) { + /* Verify that TLV length is valid against remaining buffer size */ + if (length > buf_size) { + vty_out(vty, + " PCE Info TLV size %d exceeds buffer size. Abort!\n", + length); + return buf_size; + } + + for (tlvh = ri; sum < length; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case RI_PCE_SUBTLV_ADDRESS: sum += show_vty_pce_subtlv_address(vty, tlvh); @@ -1377,7 +1446,7 @@ static uint16_t show_vty_pce_info(struct vty *vty, struct tlv_header *ri, sum += show_vty_pce_subtlv_cap_flag(vty, tlvh); break; default: - sum += show_vty_unknown_tlv(vty, tlvh); + sum += show_vty_unknown_tlv(vty, tlvh, length - sum); break; } } @@ -1391,6 +1460,8 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh) (struct ri_sr_tlv_sr_algorithm *)tlvh; int i; + check_tlv_size(ALGORITHM_COUNT, "Segment Routing Algorithm"); + if (vty != NULL) { vty_out(vty, " Segment Routing Algorithm TLV:\n"); for (i = 0; i < ntohs(algo->header.length); i++) { @@ -1409,9 +1480,7 @@ static uint16_t show_vty_sr_algorithm(struct vty *vty, struct tlv_header *tlvh) break; } } - } - - else { + } else { zlog_debug(" Segment Routing Algorithm TLV:"); for (i = 0; i < ntohs(algo->header.length); i++) switch (algo->value[i]) { @@ -1437,6 +1506,8 @@ static uint16_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; + check_tlv_size(RI_SR_TLV_LABEL_RANGE_SIZE, "SR Label Range"); + if (vty != NULL) { vty_out(vty, " Segment Routing %s Range TLV:\n" @@ -1465,6 +1536,8 @@ static uint16_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; + check_tlv_size(RI_SR_TLV_NODE_MSD_SIZE, "Node Maximum Stack Depth"); + if (vty != NULL) { vty_out(vty, " Segment Routing MSD TLV:\n" @@ -1486,9 +1559,9 @@ static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa) uint16_t length = 0, sum = 0; /* Initialize TLV browsing */ - length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; + length = lsa->size - OSPF_LSA_HEADER_SIZE; - for (tlvh = TLV_HDR_TOP(lsah); sum < length; + for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case RI_TLV_CAPABILITIES: @@ -1511,7 +1584,7 @@ static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa) break; default: - sum += show_vty_unknown_tlv(vty, tlvh); + sum += show_vty_unknown_tlv(vty, tlvh, length); break; } } diff --git a/ospfd/ospf_ri.h b/ospfd/ospf_ri.h index 4729677bca..bbad896280 100644 --- a/ospfd/ospf_ri.h +++ b/ospfd/ospf_ri.h @@ -75,7 +75,7 @@ /* RFC4970: Router Information Capabilities TLV */ /* Mandatory */ #define RI_TLV_CAPABILITIES 1 - +#define RI_TLV_CAPABILITIES_SIZE 4 struct ri_tlv_router_cap { struct tlv_header header; /* Value length is 4 bytes. */ uint32_t value; @@ -105,12 +105,12 @@ struct ri_tlv_pce { struct ri_pce_subtlv_address { /* Type = 1; Length is 8 (IPv4) or 20 (IPv6) bytes. */ struct tlv_header header; -#define PCE_ADDRESS_LENGTH_IPV4 8 -#define PCE_ADDRESS_LENGTH_IPV6 20 +#define PCE_ADDRESS_IPV4_SIZE 8 +#define PCE_ADDRESS_IPV6_SIZE 20 struct { uint16_t type; /* Address type: 1 = IPv4, 2 = IPv6 */ -#define PCE_ADDRESS_TYPE_IPV4 1 -#define PCE_ADDRESS_TYPE_IPV6 2 +#define PCE_ADDRESS_IPV4 1 +#define PCE_ADDRESS_IPV6 2 uint16_t reserved; struct in_addr value; /* PCE address */ } address; @@ -118,6 +118,7 @@ struct ri_pce_subtlv_address { /* PCE Path-Scope Sub-TLV */ /* Mandatory */ #define RI_PCE_SUBTLV_PATH_SCOPE 2 +#define RI_PCE_SUBTLV_PATH_SCOPE_SIZE 4 struct ri_pce_subtlv_path_scope { struct tlv_header header; /* Type = 2; Length = 4 bytes. */ /* @@ -128,11 +129,11 @@ struct ri_pce_subtlv_path_scope { }; /* PCE Domain Sub-TLV */ /* Optional */ -#define RI_PCE_SUBTLV_DOMAIN 3 - #define PCE_DOMAIN_TYPE_AREA 1 -#define PCE_DOMAIN_TYPE_AS 2 +#define PCE_DOMAIN_TYPE_AS 2 +#define RI_PCE_SUBTLV_DOMAIN 3 +#define RI_PCE_SUBTLV_DOMAIN_SIZE 8 struct ri_pce_subtlv_domain { struct tlv_header header; /* Type = 3; Length = 8 bytes. */ uint16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */ @@ -142,6 +143,7 @@ struct ri_pce_subtlv_domain { /* PCE Neighbor Sub-TLV */ /* Mandatory if R or S bit is set */ #define RI_PCE_SUBTLV_NEIGHBOR 4 +#define RI_PCE_SUBTLV_NEIGHBOR_SIZE 8 struct ri_pce_subtlv_neighbor { struct tlv_header header; /* Type = 4; Length = 8 bytes. */ uint16_t type; /* Domain type: 1 = OSPF Area ID, 2 = AS Number */ @@ -151,6 +153,7 @@ struct ri_pce_subtlv_neighbor { /* PCE Capabilities Flags Sub-TLV */ /* Optional */ #define RI_PCE_SUBTLV_CAP_FLAG 5 +#define RI_PCE_SUBTLV_CAP_FLAG_SIZE 4 #define PCE_CAP_GMPLS_LINK 0x0001 #define PCE_CAP_BIDIRECTIONAL 0x0002 diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index d003f3bf7c..3ce177618f 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -954,7 +954,7 @@ static inline void update_adj_sid(struct sr_nhlfe n1, struct sr_nhlfe n2) */ /* Extended Link SubTLVs Getter */ -static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh) +static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh, size_t size) { struct sr_link *srl; @@ -966,13 +966,20 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh) struct tlv_header *sub_tlvh; uint16_t length = 0, sum = 0, i = 0; + /* Check TLV size */ + if ((ntohs(tlvh->length) > size) + || ntohs(tlvh->length) < EXT_TLV_LINK_SIZE) { + zlog_warn("Wrong Extended Link TLV size. Abort!"); + return NULL; + } + srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link)); /* Initialize TLV browsing */ length = ntohs(tlvh->length) - EXT_TLV_LINK_SIZE; sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE + EXT_TLV_LINK_SIZE); - for (; sum < length; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) { + for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) { switch (ntohs(sub_tlvh->type)) { case EXT_SUBTLV_ADJ_SID: adj_sid = (struct ext_subtlv_adj_sid *)sub_tlvh; @@ -1025,7 +1032,8 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh) } /* Extended Prefix SubTLVs Getter */ -static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh) +static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh, + size_t size) { struct sr_prefix *srp; @@ -1035,13 +1043,20 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh) struct tlv_header *sub_tlvh; uint16_t length = 0, sum = 0; + /* Check TLV size */ + if ((ntohs(tlvh->length) > size) + || ntohs(tlvh->length) < EXT_TLV_PREFIX_SIZE) { + zlog_warn("Wrong Extended Link TLV size. Abort!"); + return NULL; + } + srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix)); /* Initialize TLV browsing */ length = ntohs(tlvh->length) - EXT_TLV_PREFIX_SIZE; sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE + EXT_TLV_PREFIX_SIZE); - for (; sum < length; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) { + for (; sum < length && sub_tlvh; sub_tlvh = TLV_HDR_NEXT(sub_tlvh)) { switch (ntohs(sub_tlvh->type)) { case EXT_SUBTLV_PREFIX_SID: psid = (struct ext_subtlv_prefix_sid *)sub_tlvh; @@ -1353,7 +1368,7 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) /* Collect Router Information Sub TLVs */ /* Initialize TLV browsing */ - length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; + length = lsa->size - OSPF_LSA_HEADER_SIZE; srgb.range_size = 0; srgb.lower_bound = 0; @@ -1362,24 +1377,20 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa) switch (ntohs(tlvh->type)) { case RI_SR_TLV_SR_ALGORITHM: algo = (struct ri_sr_tlv_sr_algorithm *)tlvh; - sum += TLV_SIZE(tlvh); break; case RI_SR_TLV_SRGB_LABEL_RANGE: ri_srgb = (struct ri_sr_tlv_sid_label_range *)tlvh; - sum += TLV_SIZE(tlvh); break; case RI_SR_TLV_SRLB_LABEL_RANGE: ri_srlb = (struct ri_sr_tlv_sid_label_range *)tlvh; - sum += TLV_SIZE(tlvh); break; case RI_SR_TLV_NODE_MSD: msd = ((struct ri_sr_tlv_node_msd *)(tlvh))->value; - sum += TLV_SIZE(tlvh); break; default: - sum += TLV_SIZE(tlvh); break; } + sum += TLV_SIZE(tlvh); } /* Check if Segment Routing Capabilities has been found */ @@ -1519,7 +1530,7 @@ void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa) struct lsa_header *lsah = lsa->data; struct sr_link *srl; - uint16_t length, sum; + int length; osr_debug("SR (%s): Process Extended Link LSA 8.0.0.%u from %pI4", __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), @@ -1546,20 +1557,19 @@ void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa) } /* Initialize TLV browsing */ - length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; - sum = 0; - for (tlvh = TLV_HDR_TOP(lsah); (sum < length) && (tlvh != NULL); + length = lsa->size - OSPF_LSA_HEADER_SIZE; + for (tlvh = TLV_HDR_TOP(lsah); length > 0 && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { if (ntohs(tlvh->type) == EXT_TLV_LINK) { /* Got Extended Link information */ - srl = get_ext_link_sid(tlvh); + srl = get_ext_link_sid(tlvh, length); /* Update SID if not null */ if (srl != NULL) { srl->instance = ntohl(lsah->id.s_addr); update_ext_link_sid(srn, srl, lsa->flags); } } - sum += TLV_SIZE(tlvh); + length -= TLV_SIZE(tlvh); } } @@ -1753,7 +1763,7 @@ void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa) struct lsa_header *lsah = (struct lsa_header *)lsa->data; struct sr_prefix *srp; - uint16_t length, sum; + int length; osr_debug("SR (%s): Process Extended Prefix LSA 7.0.0.%u from %pI4", __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)), @@ -1780,20 +1790,19 @@ void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa) } /* Initialize TLV browsing */ - length = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; - sum = 0; - for (tlvh = TLV_HDR_TOP(lsah); sum < length; + length = lsa->size - OSPF_LSA_HEADER_SIZE; + for (tlvh = TLV_HDR_TOP(lsah); length > 0 && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { if (ntohs(tlvh->type) == EXT_TLV_LINK) { /* Got Extended Link information */ - srp = get_ext_prefix_sid(tlvh); + srp = get_ext_prefix_sid(tlvh, length); /* Update SID if not null */ if (srp != NULL) { srp->instance = ntohl(lsah->id.s_addr); update_ext_prefix_sid(srn, srp); } } - sum += TLV_SIZE(tlvh); + length -= TLV_SIZE(tlvh); } } diff --git a/ospfd/ospf_sr.h b/ospfd/ospf_sr.h index f00d8e1b0b..ea54e3b310 100644 --- a/ospfd/ospf_sr.h +++ b/ospfd/ospf_sr.h @@ -100,6 +100,7 @@ struct ri_sr_tlv_sid_label_range { /* RI Node/MSD TLV as per RFC 8476 */ #define RI_SR_TLV_NODE_MSD 12 +#define RI_SR_TLV_NODE_MSD_SIZE 4 struct ri_sr_tlv_node_msd { struct tlv_header header; uint8_t subtype; /* always = 1 */ diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 1929e3dea4..0946e51077 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -1882,7 +1882,7 @@ static int ospf_te_parse_router_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) struct ls_edge *edge; struct ls_subnet *subnet; struct listnode *node; - int len; + int len, links; /* Sanity Check */ if (!ted || !lsa || !lsa->data) @@ -1932,8 +1932,9 @@ static int ospf_te_parse_router_lsa(struct ls_ted *ted, struct ospf_lsa *lsa) subnet->status = ORPHAN; /* Then, process Link Information */ - len = ntohs(rl->header.length) - 4; - for (int i = 0; i < ntohs(rl->links) && len > 0; len -= 12, i++) { + len = lsa->size - OSPF_LSA_HEADER_SIZE - OSPF_ROUTER_LSA_MIN_SIZE; + links = ntohs(rl->links); + for (int i = 0; i < links && len > 0; len -= 12, i++) { struct prefix p; uint32_t metric; @@ -2152,20 +2153,20 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) /* Initialize TLV browsing */ tlvh = TLV_HDR_TOP(lsa->data); + len = lsa->size - OSPF_LSA_HEADER_SIZE; - uint32_t total_len = TLV_BODY_SIZE(lsa->data) - OSPF_LSA_HEADER_SIZE; + /* Check if TE Router-ID TLV is present */ + if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR) { + /* if TE Router-ID is alone, we are done ... */ + if (len == TE_LINK_SUBTLV_DEF_SIZE) + return 0; - /* If TE Router-ID is only TLV we are done */ - if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR - && total_len == sizeof(struct te_tlv_router_addr)) - return 0; - - /* Skip TE Router-ID if present */ - if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR) + /* ... otherwise, skip it */ + len -= TE_LINK_SUBTLV_DEF_SIZE + TLV_HDR_SIZE; tlvh = TLV_HDR_NEXT(tlvh); + } - /* Check if we have a TE Link TLV */ - len = TLV_BODY_SIZE(tlvh); + /* Check if we have a valid TE Link TLV */ if ((len == 0) || (ntohs(tlvh->type) != TE_TLV_LINK)) return 0; @@ -2467,8 +2468,9 @@ static int ospf_te_parse_ri(struct ls_ted *ted, struct ospf_lsa *lsa) &lsa->data->id, &node->router_id); /* Initialize TLV browsing */ - len = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; - for (tlvh = TLV_HDR_TOP(lsah); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { + len = lsa->size - OSPF_LSA_HEADER_SIZE; + for (tlvh = TLV_HDR_TOP(lsah); sum < len && tlvh; + tlvh = TLV_HDR_NEXT(tlvh)) { struct ri_sr_tlv_sr_algorithm *algo; struct ri_sr_tlv_sid_label_range *range; struct ri_sr_tlv_node_msd *msd; @@ -3152,11 +3154,25 @@ static void ospf_te_init_ted(struct ls_ted *ted, struct ospf *ospf) /*------------------------------------------------------------------------* * Followings are vty session control functions. *------------------------------------------------------------------------*/ +#define check_tlv_size(size, msg) \ + do { \ + if (ntohs(tlvh->length) > size) { \ + if (vty != NULL) \ + vty_out(vty, " Wrong %s TLV size: %d(%d)\n", \ + msg, ntohs(tlvh->length), size); \ + else \ + zlog_debug(" Wrong %s TLV size: %d(%d)\n", \ + msg, ntohs(tlvh->length), size); \ + return size + TLV_HDR_SIZE; \ + } \ + } while(0) static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh) { struct te_tlv_router_addr *top = (struct te_tlv_router_addr *)tlvh; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Router Address"); + if (vty != NULL) vty_out(vty, " Router-Address: %pI4\n", &top->value); else @@ -3165,10 +3181,23 @@ static uint16_t show_vty_router_addr(struct vty *vty, struct tlv_header *tlvh) return TLV_SIZE(tlvh); } -static uint16_t show_vty_link_header(struct vty *vty, struct tlv_header *tlvh) +static uint16_t show_vty_link_header(struct vty *vty, struct tlv_header *tlvh, + size_t buf_size) { struct te_tlv_link *top = (struct te_tlv_link *)tlvh; + if (TLV_SIZE(tlvh) > buf_size) { + if (vty != NULL) + vty_out(vty, + " TLV size %d exceeds buffer size. Abort!", + TLV_SIZE(tlvh)); + else + zlog_debug( + " TLV size %d exceeds buffer size. Abort!", + TLV_SIZE(tlvh)); + return buf_size; + } + if (vty != NULL) vty_out(vty, " Link: %u octets of data\n", ntohs(top->header.length)); @@ -3185,6 +3214,8 @@ static uint16_t show_vty_link_subtlv_link_type(struct vty *vty, struct te_link_subtlv_link_type *top; const char *cp = "Unknown"; + check_tlv_size(TE_LINK_SUBTLV_TYPE_SIZE, "Link Type"); + top = (struct te_link_subtlv_link_type *)tlvh; switch (top->link_type.value) { case LINK_TYPE_SUBTLV_VALUE_PTP: @@ -3211,6 +3242,8 @@ static uint16_t show_vty_link_subtlv_link_id(struct vty *vty, { struct te_link_subtlv_link_id *top; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Link ID"); + top = (struct te_link_subtlv_link_id *)tlvh; if (vty != NULL) vty_out(vty, " Link-ID: %pI4\n", &top->value); @@ -3221,11 +3254,24 @@ static uint16_t show_vty_link_subtlv_link_id(struct vty *vty, } static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + size_t buf_size) { struct te_link_subtlv_lclif_ipaddr *top; int i, n; + if (TLV_SIZE(tlvh) > buf_size) { + if (vty != NULL) + vty_out(vty, + " TLV size %d exceeds buffer size. Abort!", + TLV_SIZE(tlvh)); + else + zlog_debug( + " TLV size %d exceeds buffer size. Abort!", + TLV_SIZE(tlvh)); + return buf_size; + } + top = (struct te_link_subtlv_lclif_ipaddr *)tlvh; n = ntohs(tlvh->length) / sizeof(top->value[0]); @@ -3244,11 +3290,24 @@ static uint16_t show_vty_link_subtlv_lclif_ipaddr(struct vty *vty, } static uint16_t show_vty_link_subtlv_rmtif_ipaddr(struct vty *vty, - struct tlv_header *tlvh) + struct tlv_header *tlvh, + size_t buf_size) { struct te_link_subtlv_rmtif_ipaddr *top; int i, n; + if (TLV_SIZE(tlvh) > buf_size) { + if (vty != NULL) + vty_out(vty, + " TLV size %d exceeds buffer size. Abort!", + TLV_SIZE(tlvh)); + else + zlog_debug( + " TLV size %d exceeds buffer size. Abort!", + TLV_SIZE(tlvh)); + return buf_size; + } + top = (struct te_link_subtlv_rmtif_ipaddr *)tlvh; n = ntohs(tlvh->length) / sizeof(top->value[0]); if (vty != NULL) @@ -3270,6 +3329,8 @@ static uint16_t show_vty_link_subtlv_te_metric(struct vty *vty, { struct te_link_subtlv_te_metric *top; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "TE Metric"); + top = (struct te_link_subtlv_te_metric *)tlvh; if (vty != NULL) vty_out(vty, " Traffic Engineering Metric: %u\n", @@ -3287,6 +3348,8 @@ static uint16_t show_vty_link_subtlv_max_bw(struct vty *vty, struct te_link_subtlv_max_bw *top; float fval; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Maximum Bandwidth"); + top = (struct te_link_subtlv_max_bw *)tlvh; fval = ntohf(top->value); @@ -3304,6 +3367,8 @@ static uint16_t show_vty_link_subtlv_max_rsv_bw(struct vty *vty, struct te_link_subtlv_max_rsv_bw *top; float fval; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Maximum Reservable Bandwidth"); + top = (struct te_link_subtlv_max_rsv_bw *)tlvh; fval = ntohf(top->value); @@ -3324,6 +3389,8 @@ static uint16_t show_vty_link_subtlv_unrsv_bw(struct vty *vty, float fval1, fval2; int i; + check_tlv_size(TE_LINK_SUBTLV_UNRSV_SIZE, "Unreserved Bandwidth"); + top = (struct te_link_subtlv_unrsv_bw *)tlvh; if (vty != NULL) vty_out(vty, @@ -3353,6 +3420,8 @@ static uint16_t show_vty_link_subtlv_rsc_clsclr(struct vty *vty, { struct te_link_subtlv_rsc_clsclr *top; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Resource class/color"); + top = (struct te_link_subtlv_rsc_clsclr *)tlvh; if (vty != NULL) vty_out(vty, " Resource class/color: 0x%x\n", @@ -3369,6 +3438,8 @@ static uint16_t show_vty_link_subtlv_lrrid(struct vty *vty, { struct te_link_subtlv_lrrid *top; + check_tlv_size(TE_LINK_SUBTLV_LRRID_SIZE, "Local/Remote Router ID"); + top = (struct te_link_subtlv_lrrid *)tlvh; if (vty != NULL) { @@ -3391,6 +3462,8 @@ static uint16_t show_vty_link_subtlv_llri(struct vty *vty, { struct te_link_subtlv_llri *top; + check_tlv_size(TE_LINK_SUBTLV_LLRI_SIZE, "Link Local/Remote ID"); + top = (struct te_link_subtlv_llri *)tlvh; if (vty != NULL) { @@ -3413,6 +3486,8 @@ static uint16_t show_vty_link_subtlv_rip(struct vty *vty, { struct te_link_subtlv_rip *top; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Remote ASBR Address"); + top = (struct te_link_subtlv_rip *)tlvh; if (vty != NULL) @@ -3430,6 +3505,8 @@ static uint16_t show_vty_link_subtlv_ras(struct vty *vty, { struct te_link_subtlv_ras *top; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Remote AS number"); + top = (struct te_link_subtlv_ras *)tlvh; if (vty != NULL) @@ -3449,6 +3526,8 @@ static uint16_t show_vty_link_subtlv_av_delay(struct vty *vty, uint32_t delay; uint32_t anomalous; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Average Link Delay"); + top = (struct te_link_subtlv_av_delay *)tlvh; delay = (uint32_t)ntohl(top->value) & TE_EXT_MASK; anomalous = (uint32_t)ntohl(top->value) & TE_EXT_ANORMAL; @@ -3470,6 +3549,8 @@ static uint16_t show_vty_link_subtlv_mm_delay(struct vty *vty, uint32_t low, high; uint32_t anomalous; + check_tlv_size(TE_LINK_SUBTLV_MM_DELAY_SIZE, "Min/Max Link Delay"); + top = (struct te_link_subtlv_mm_delay *)tlvh; low = (uint32_t)ntohl(top->low) & TE_EXT_MASK; anomalous = (uint32_t)ntohl(top->low) & TE_EXT_ANORMAL; @@ -3491,6 +3572,8 @@ static uint16_t show_vty_link_subtlv_delay_var(struct vty *vty, struct te_link_subtlv_delay_var *top; uint32_t jitter; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Link Delay Variation"); + top = (struct te_link_subtlv_delay_var *)tlvh; jitter = (uint32_t)ntohl(top->value) & TE_EXT_MASK; @@ -3510,6 +3593,8 @@ static uint16_t show_vty_link_subtlv_pkt_loss(struct vty *vty, uint32_t anomalous; float fval; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Link Loss"); + top = (struct te_link_subtlv_pkt_loss *)tlvh; loss = (uint32_t)ntohl(top->value) & TE_EXT_MASK; fval = (float)(loss * LOSS_PRECISION); @@ -3531,6 +3616,8 @@ static uint16_t show_vty_link_subtlv_res_bw(struct vty *vty, struct te_link_subtlv_res_bw *top; float fval; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Residual Bandwidth"); + top = (struct te_link_subtlv_res_bw *)tlvh; fval = ntohf(top->value); @@ -3552,6 +3639,8 @@ static uint16_t show_vty_link_subtlv_ava_bw(struct vty *vty, struct te_link_subtlv_ava_bw *top; float fval; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Available Bandwidth"); + top = (struct te_link_subtlv_ava_bw *)tlvh; fval = ntohf(top->value); @@ -3573,6 +3662,8 @@ static uint16_t show_vty_link_subtlv_use_bw(struct vty *vty, struct te_link_subtlv_use_bw *top; float fval; + check_tlv_size(TE_LINK_SUBTLV_DEF_SIZE, "Utilized Bandwidth"); + top = (struct te_link_subtlv_use_bw *)tlvh; fval = ntohf(top->value); @@ -3588,8 +3679,21 @@ static uint16_t show_vty_link_subtlv_use_bw(struct vty *vty, return TLV_SIZE(tlvh); } -static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh) +static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh, + size_t buf_size) { + if (TLV_SIZE(tlvh) > buf_size) { + if (vty != NULL) + vty_out(vty, + " TLV size %d exceeds buffer size. Abort!", + TLV_SIZE(tlvh)); + else + zlog_debug( + " TLV size %d exceeds buffer size. Abort!", + TLV_SIZE(tlvh)); + return buf_size; + } + if (vty != NULL) vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n", ntohs(tlvh->type), ntohs(tlvh->length)); @@ -3607,8 +3711,7 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, struct tlv_header *tlvh; uint16_t sum = subtotal; - for (tlvh = tlvh0; sum < total; - tlvh = TLV_HDR_NEXT(tlvh)) { + for (tlvh = tlvh0; sum < total; tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case TE_LINK_SUBTLV_LINK_TYPE: sum += show_vty_link_subtlv_link_type(vty, tlvh); @@ -3617,10 +3720,12 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, sum += show_vty_link_subtlv_link_id(vty, tlvh); break; case TE_LINK_SUBTLV_LCLIF_IPADDR: - sum += show_vty_link_subtlv_lclif_ipaddr(vty, tlvh); + sum += show_vty_link_subtlv_lclif_ipaddr(vty, tlvh, + total - sum); break; case TE_LINK_SUBTLV_RMTIF_IPADDR: - sum += show_vty_link_subtlv_rmtif_ipaddr(vty, tlvh); + sum += show_vty_link_subtlv_rmtif_ipaddr(vty, tlvh, + total - sum); break; case TE_LINK_SUBTLV_TE_METRIC: sum += show_vty_link_subtlv_te_metric(vty, tlvh); @@ -3671,7 +3776,7 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, sum += show_vty_link_subtlv_use_bw(vty, tlvh); break; default: - sum += show_vty_unknown_tlv(vty, tlvh); + sum += show_vty_unknown_tlv(vty, tlvh, total - sum); break; } } @@ -3687,9 +3792,9 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa) uint16_t subtotal, uint16_t total) = NULL; sum = 0; - total = ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE; + total = lsa->size - OSPF_LSA_HEADER_SIZE; - for (tlvh = TLV_HDR_TOP(lsah); sum < total; + for (tlvh = TLV_HDR_TOP(lsah); sum < total && tlvh; tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) { if (subfunc != NULL) { sum = (*subfunc)(vty, tlvh, sum, total); @@ -3704,12 +3809,12 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa) sum += show_vty_router_addr(vty, tlvh); break; case TE_TLV_LINK: - sum += show_vty_link_header(vty, tlvh); + sum += show_vty_link_header(vty, tlvh, total - sum); subfunc = ospf_mpls_te_show_link_subtlv; next = TLV_DATA(tlvh); break; default: - sum += show_vty_unknown_tlv(vty, tlvh); + sum += show_vty_unknown_tlv(vty, tlvh, total - sum); break; } } @@ -4081,10 +4186,12 @@ static void show_mpls_te_link_sub(struct vty *vty, struct interface *ifp) show_vty_link_subtlv_link_id(vty, &lp->link_id.header); if (TLV_TYPE(lp->lclif_ipaddr) != 0) show_vty_link_subtlv_lclif_ipaddr( - vty, &lp->lclif_ipaddr.header); + vty, &lp->lclif_ipaddr.header, + lp->lclif_ipaddr.header.length); if (TLV_TYPE(lp->rmtif_ipaddr) != 0) show_vty_link_subtlv_rmtif_ipaddr( - vty, &lp->rmtif_ipaddr.header); + vty, &lp->rmtif_ipaddr.header, + lp->rmtif_ipaddr.header.length); if (TLV_TYPE(lp->rip) != 0) show_vty_link_subtlv_rip(vty, &lp->rip.header); if (TLV_TYPE(lp->ras) != 0) diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 50943c4ccf..04b6bdd961 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -6400,6 +6400,7 @@ static int show_network_lsa_detail(struct vty *vty, struct ospf_lsa *lsa, if (lsa != NULL) { struct network_lsa *nl = (struct network_lsa *)lsa->data; + struct in_addr *addr; show_ip_ospf_database_header(vty, lsa, json); @@ -6410,24 +6411,25 @@ static int show_network_lsa_detail(struct vty *vty, struct ospf_lsa *lsa, json_object_int_add(json, "networkMask", ip_masklen(nl->mask)); - length = ntohs(lsa->data->length) - OSPF_LSA_HEADER_SIZE - 4; - - for (i = 0; length > 0; i++, length -= 4) + length = lsa->size - OSPF_LSA_HEADER_SIZE - 4; + addr = &nl->routers[0]; + for (i = 0; length > 0 && addr; + length -= 4, addr = &nl->routers[++i]) if (!json) { vty_out(vty, " Attached Router: %pI4\n", - &nl->routers[i]); + addr); vty_out(vty, "\n"); } else { json_router = json_object_new_object(); json_object_string_add( json_router, "attachedRouterId", - inet_ntop(AF_INET, &nl->routers[i], - buf, sizeof(buf))); - json_object_object_add( - json_attached_rt, - inet_ntop(AF_INET, &(nl->routers[i]), - buf, sizeof(buf)), - json_router); + inet_ntop(AF_INET, addr, buf, + sizeof(buf))); + json_object_object_add(json_attached_rt, + inet_ntop(AF_INET, addr, + buf, + sizeof(buf)), + json_router); } } diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index cc1404e5e9..7505f24aef 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -2182,6 +2182,16 @@ static void ospf_set_redist_vrf_bitmaps(struct ospf *ospf, bool set) vrf_bitmap_unset(zclient->redist[AFI_IP][type], ospf->vrf_id); } + + red_list = ospf->redist[DEFAULT_ROUTE]; + if (red_list) { + if (set) + vrf_bitmap_set(zclient->default_information[AFI_IP], + ospf->vrf_id); + else + vrf_bitmap_unset(zclient->default_information[AFI_IP], + ospf->vrf_id); + } } /* Enable OSPF VRF instance */ diff --git a/pathd/path_cli.c b/pathd/path_cli.c index 7a28449e4e..172737c9d4 100644 --- a/pathd/path_cli.c +++ b/pathd/path_cli.c @@ -351,8 +351,6 @@ static int segment_list_has_src_dst( nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "ipv6_adjacency"); node_src_id = adj_src_ipv6_str; - } else { - return CMD_ERR_NO_MATCH; } /* addresses */ snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address", @@ -421,8 +419,6 @@ int segment_list_has_prefix( sizeof(buf_prefix)); pre_ipaddr.ipa_type = IPADDR_V6; pre_ipaddr.ip._v6_addr = prefix_cli.u.prefix6; - } else { - return CMD_ERR_NO_MATCH; } snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address", index_str); @@ -524,7 +520,7 @@ DEFPY(srte_segment_list_segment, srte_segment_list_segment_cmd, if (status != CMD_SUCCESS) return status; } else { - segment_list_has_prefix( + status = segment_list_has_prefix( vty, xpath, index, index_str, prefix_ipv4, prefix_ipv4_str, prefix_ipv6, prefix_ipv6_str, has_algo, algo, algo_str, has_iface_id, iface_id, iface_id_str); @@ -821,9 +817,8 @@ DEFPY(srte_candidate_no_bandwidth, return nb_cli_apply_changes(vty, NULL); } -DEFPY(srte_candidate_affinity_filter, - srte_candidate_affinity_filter_cmd, - "affinity {exclude-any|include-any|include-all}$type BITPATTERN$value", +DEFPY(srte_candidate_affinity_filter, srte_candidate_affinity_filter_cmd, + "affinity <exclude-any|include-any|include-all>$type BITPATTERN$value", "Affinity constraint\n" "Exclude any matching link\n" "Include any matching link\n" @@ -846,9 +841,8 @@ DEFPY(srte_candidate_affinity_filter, return nb_cli_apply_changes(vty, NULL); } -DEFPY(srte_candidate_no_affinity_filter, - srte_candidate_no_affinity_filter_cmd, - "no affinity {exclude-any|include-any|include-all}$type [BITPATTERN$value]", +DEFPY(srte_candidate_no_affinity_filter, srte_candidate_no_affinity_filter_cmd, + "no affinity <exclude-any|include-any|include-all>$type [BITPATTERN$value]", NO_STR "Affinity constraint\n" "Exclude any matching link\n" diff --git a/pathd/path_pcep_pcc.c b/pathd/path_pcep_pcc.c index 9af2148819..779c400b86 100644 --- a/pathd/path_pcep_pcc.c +++ b/pathd/path_pcep_pcc.c @@ -1273,7 +1273,8 @@ void handle_pcep_comp_reply(struct ctrl_state *ctrl_state, * pathd API is thread safe, we could get a new path */ if (pcc_state->caps.is_stateful) { PCEP_DEBUG("%s Delegating undefined dynamic path %s to PCE %s", - pcc_state->tag, path->name, pcc_state->originator); + pcc_state->tag, req->path->name, + pcc_state->originator); path = pcep_copy_path(req->path); path->is_delegated = true; send_report(pcc_state, path); diff --git a/pathd/pathd.c b/pathd/pathd.c index 2462b08306..9dc3a41638 100644 --- a/pathd/pathd.c +++ b/pathd/pathd.c @@ -195,14 +195,16 @@ int srte_segment_entry_set_nai(struct srte_segment_entry *segment, struct ipaddr *remote_ip, uint32_t remote_iface, uint8_t algo, uint8_t pref_len) { + int32_t status = 0; struct prefix pre = {0}; - segment->nai_type = type; - memcpy(&segment->nai_local_addr, local_ip, sizeof(struct ipaddr)); if (!segment || !local_ip || !remote_ip) return 1; + segment->nai_type = type; + memcpy(&segment->nai_local_addr, local_ip, sizeof(struct ipaddr)); + switch (type) { case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE: case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE: diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index ba6004861e..5a904423c2 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -1788,6 +1788,7 @@ def create_interfaces_cfg(tgen, topo, build=False): "network", "priority", "cost", + "mtu_ignore" ] if "ospf" in data: interface_data += _create_interfaces_ospf_cfg( diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 04a12d0eec..7ad64de4a1 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -352,6 +352,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config= data_ospf_auth = ospf_data.setdefault("authentication", None) data_ospf_dr_priority = ospf_data.setdefault("priority", None) data_ospf_cost = ospf_data.setdefault("cost", None) + data_ospf_mtu = ospf_data.setdefault("mtu_ignore", None) try: intf = topo["routers"][router]["links"][lnk]["interface"] @@ -400,19 +401,26 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config= config_data.append(cmd) # interface ospf dr priority - if data_ospf_dr_priority in ospf_data: + if data_ospf_dr_priority: cmd = "ip ospf priority {}".format(ospf_data["priority"]) if "del_action" in ospf_data: cmd = "no {}".format(cmd) config_data.append(cmd) # interface ospf cost - if data_ospf_cost in ospf_data: + if data_ospf_cost: cmd = "ip ospf cost {}".format(ospf_data["cost"]) if "del_action" in ospf_data: cmd = "no {}".format(cmd) config_data.append(cmd) + # interface ospf mtu + if data_ospf_mtu: + cmd = "ip ospf mtu-ignore" + if 'del_action' in ospf_data: + cmd = "no {}".format(cmd) + config_data.append(cmd) + if build: return config_data else: diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index 1432a82b12..9dfde325f6 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -62,6 +62,8 @@ from lib.ospf import ( verify_ospf_rib, create_router_ospf, redistribute_ospf, + config_ospf_interface, + verify_ospf_interface, ) # Global variables @@ -576,6 +578,89 @@ def test_ospf_redistribution_tc8_p1(request): write_test_footer(tc_name) +def test_ospf_cost_tc52_p0(request): + """OSPF Cost - verifying ospf interface cost functionality""" + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + global topo + step("Bring up the base config.") + reset_config_on_routers(tgen) + + step( + "Configure ospf cost as 20 on interface between R0 and R1. " + "Configure ospf cost as 30 between interface between R0 and R2." + ) + + r0_ospf_cost = { + "r0": {"links": {"r1": {"ospf": {"cost": 20}}, "r2": {"ospf": {"cost": 30}}}} + } + result = config_ospf_interface(tgen, topo, r0_ospf_cost) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that cost is updated in the ospf interface between" + " r0 and r1 as 30 and r0 and r2 as 20" + ) + dut = "r0" + result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=r0_ospf_cost) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step( + "Swap the costs between interfaces on r0, between r0 and r1 to 30" + ", r0 and r2 to 20" + ) + + r0_ospf_cost = { + "r0": {"links": {"r1": {"ospf": {"cost": 30}}, "r2": {"ospf": {"cost": 20}}}} + } + result = config_ospf_interface(tgen, topo, r0_ospf_cost) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that cost is updated in the ospf interface between r0 " + "and r1 as 30 and r0 and r2 as 20." + ) + result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=r0_ospf_cost) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step(" Un configure cost from the interface r0 - r1.") + + r0_ospf_cost = {"r0": {"links": {"r1": {"ospf": {"cost": 30, "del_action": True}}}}} + result = config_ospf_interface(tgen, topo, r0_ospf_cost) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + input_dict = { + "r0": {"links": {"r1": {"ospf": {"cost": 10}}, "r2": {"ospf": {"cost": 20}}}} + } + step( + "Verify that cost is updated in the ospf interface between r0" + " and r1 as 10 and r0 and r2 as 20." + ) + + result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step(" Un configure cost from the interface r0 - r2.") + + r0_ospf_cost = {"r0": {"links": {"r2": {"ospf": {"cost": 20, "del_action": True}}}}} + result = config_ospf_interface(tgen, topo, r0_ospf_cost) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step( + "Verify that cost is updated in the ospf interface between r0" + "and r1 as 10 and r0 and r2 as 10" + ) + + input_dict = { + "r0": {"links": {"r1": {"ospf": {"cost": 10}}, "r2": {"ospf": {"cost": 10}}}} + } + result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py index 6f6b119abc..e94680d974 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py @@ -101,6 +101,7 @@ TESTCASES = 2. OSPF Timers - Verify OSPF interface timer hello interval functionality 3. OSPF Timers - Verify OSPF interface timer dead interval functionality 4. Verify ospf show commands with json output. +5. Verify NFSM events when ospf nbr changes with different MTU values. """ @@ -976,6 +977,153 @@ def test_ospf_dead_tc11_p0(request): write_test_footer(tc_name) +def test_ospf_tc4_mtu_ignore_p0(request): + """ + OSPF NFSM - MTU change + + Verify NFSM events when ospf nbr changes with different MTU values + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + global topo + step(" Bring up the base config as per the topology") + step("Configure OSPF on all the routers of the topology.") + step("Verify that OSPF neighbors are FULL.") + reset_config_on_routers(tgen) + result = verify_ospf_neighbor(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step( + "Modify the MTU to non default Value on R0 to R1 interface. " + "Reset ospf neighbors on R0." + ) + + rtr0 = tgen.routers()["r0"] + rtr1 = tgen.routers()["r1"] + + r0_r1_intf = topo["routers"]["r0"]["links"]["r1"]["interface"] + r1_r0_intf = topo["routers"]["r1"]["links"]["r0"]["interface"] + + rtr0.run("ifconfig {} mtu 1200".format(r0_r1_intf)) + + clear_ospf(tgen, "r0") + + step( + "Verify that OSPF neighborship between R0 and R1 is stuck in Exstart" " State." + ) + result = verify_ospf_neighbor(tgen, topo, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n OSPF nbrs are Full " + "instead of Exstart. Error: {}".format(tc_name, result) + ) + + step( + "Verify that configured MTU value is updated in the show ip " "ospf interface." + ) + + dut = "r0" + input_dict = {"r0": {"links": {"r1": {"ospf": {"mtuBytes": 1200}}}}} + result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step( + "Modify the MTU to non default Value on R0 to R1 interface. " + "Reset ospf neighbors on R0." + ) + rtr0.run("ifconfig {} mtu 1500".format(r0_r1_intf)) + + clear_ospf(tgen, "r0") + + step("Verify that OSPF neighborship between R0 and R1 becomes full.") + result = verify_ospf_neighbor(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step( + "Configure mtu ignore and change the value of the mtu to non default" + " on R0 to R1 interface. Reset ospf neighbors on R0." + ) + r0_ospf_mtu = {"r0": {"links": {"r1": {"ospf": {"mtu_ignore": True}}}}} + result = config_ospf_interface(tgen, topo, r0_ospf_mtu) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + dut = "r0" + input_dict = {"r0": {"links": {"r1": {"ospf": {"mtuMismatchDetect": True}}}}} + result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + r1_ospf_mtu = {"r1": {"links": {"r0": {"ospf": {"mtu_ignore": True}}}}} + result = config_ospf_interface(tgen, topo, r1_ospf_mtu) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + rtr0.run("ifconfig {} mtu 1200".format(r0_r1_intf)) + + clear_ospf(tgen, "r0") + + step("Verify that OSPF neighborship between R0 and R1 becomes full.") + result = verify_ospf_neighbor(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step( + "Unconfigure mtu-ignore command from the interface. " + "Reset ospf neighbors on R0." + ) + + r1_ospf_mtu = { + "r1": {"links": {"r0": {"ospf": {"mtu_ignore": True, "delete": True}}}} + } + result = config_ospf_interface(tgen, topo, r1_ospf_mtu) + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + clear_ospf(tgen, "r0") + + step( + "Verify that OSPF neighborship between R0 and R1 is stuck in Exstart" " State." + ) + result = verify_ospf_neighbor(tgen, topo, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n OSPF nbrs are Full " + "instead of Exstart. Error: {}".format(tc_name, result) + ) + + step("Modify the MTU to again default valaue on R0 to R1 interface.") + + rtr0.run("ifconfig {} mtu 1500".format(r0_r1_intf)) + + clear_ospf(tgen, "r0") + + step("Verify that OSPF neighborship between R0 and R1 becomes full.") + result = verify_ospf_neighbor(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step( + "Configure ospf interface with jumbo MTU (9216)." "Reset ospf neighbors on R0." + ) + + rtr0.run("ifconfig {} mtu 9216".format(r0_r1_intf)) + rtr1.run("ifconfig {} mtu 9216".format(r1_r0_intf)) + + clear_ospf(tgen, "r0") + clear_ospf(tgen, "r1") + + step("Verify that OSPF neighborship between R0 and R1 becomes full.") + result = verify_ospf_neighbor(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify that jumbo MTU is updated in the show ip ospf interface.") + dut = "r0" + input_dict = {"r0": {"links": {"r1": {"ospf": {"mtuBytes": 9216}}}}} + result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) |
