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>
This commit is contained in:
Olivier Dugeon 2018-01-18 19:11:11 +01:00
parent b782607f7f
commit cf9b9f77f6
25 changed files with 5096 additions and 86 deletions

82
doc/OSPF-SR.rst Normal file
View File

@ -0,0 +1,82 @@
OSPF Segment Routing
====================
This is an EXPERIMENTAL support of draft draft-ietf-ospf-segment-routing-extensions-24.
DON'T use it for production network.
Implementation details
----------------------
Segment Routing used 3 differents OPAQUE LSA in OSPF to carry the various information:
- Router Information: flood the Segment Routing capabilities of the node. This include
the supported algorithms, the Segment Routing Global Block (SRGB) and the Maximum Stack
Depth.
- Extended Link: flood the Adjaceny and Lan Adjacency Segment Identifier
- Extended Prefix: flood the Prefix Segment Identifier
The implementation follow previous TE and Router Information code. It used the OPAQUE LSA
functions define in ospf_opaque.[c,h] as well as the OSPF API. This latter is mandatory
for the implementation as it provides the Callback to Segment Routing functions (see below)
when an Extended Link / Prefix or Router Information is received.
Following files where modified or added:
- ospd_ri.[c,h] have been modified to add the new TLVs for Segment Routing.
- ospf_ext.[c,h] implement RFC7684 as base support of Extended Link and Prefix Opaque LSA.
- ospf_sr.[c,h] implement the earth of Segment Routing. It adds a new Segment Routing database
to manage Segment Identifiers per Link and Prefix and Segment Routing enable node, Callback
functions to process incoming LSA and install MPLS FIB entry through Zebra.
the figure below shows the relation between the various files:
- ospf_sr.c centralized all the Segment Routing processing. It receives Opaque LSA
Router Information (4.0.0.0) from ospf_ri.c and Extended Prefix (7.0.0.X) Link (8.0.0.X)
from ospf_ext.c. Once received, it parse TLVs and SubTLVs and store information in SRDB
(which is defined in ospf_sr.h). For each received LSA, NHLFE is computed and send to
Zebra to add/remove new MPLS labels entries and FEC. New CLI configurations are also
centralized in ospf_sr.c. This CLI will trigger the flooding os new LSA Router Information
(4.0.0.0), Extended Prefix (7.0.0.X) and Link (8.0.0.X) by ospf_ri.c, respectively ospf_ext.c.
- ospf_ri.c send back to ospf_sr.c received Router Information LSA and update self Router
Information LSA with paramters provided by ospf_sr.c i.e. SRGB and MSD. It use ospf_opaque.c
functions to send / received these Opaque LSAs.
- ospf_ext.c send bacl to ospf_sr.c received Extended Prefix and Link Opaque LSA and send
self Extended Prefix and Link Opaque LSA through ospf_opaque.c functions.
+-----------+ +-------+
| | | |
| ospf_sr.c +-----+ SRDB |
+-----------+ +--+ | |
| +-^-------^-+ | +-------+
| | | | |
| | | | |
| | | | +--------+
| | | | |
+---v----------+ | | | +-----v-------+
| | | | | | |
| ospf_ri.c +--+ | +-------+ ospf_ext.c |
| LSA 4.0.0.0 | | | LSA 7.0.0.X |
| | | | LSA 8.0.0.X |
+---^----------+ | | |
| | +-----^-------+
| | |
| | |
| +--------v------------+ |
| | | |
| | ZEBRA: Labels + FEC | |
| | | |
| +---------------------+ |
| |
| |
| +---------------+ |
| | | |
+---------> ospf_opaque.c <---------+
| |
+---------------+
Known limitations
-----------------
- Only single Area is supported. ABR is not yet supported
- Only SPF algorithm is supported
- Extended Prefix Range is not supported

View File

@ -22,6 +22,7 @@ networks.
* Opaque LSA::
* OSPF Traffic Engineering::
* Router Information::
* Segment Routing::
* Debugging OSPF::
* OSPF Configuration Examples::
@end menu
@ -724,6 +725,44 @@ Show Router Capabilities flag.
Show Router Capabilities PCE parameters.
@end deffn
@node Segment Routing
@section Segment Routing
This is an EXPERIMENTAL support of Segment Routing as per draft
draft-ietf-ospf-segment-routing-extensions-24i for MPLS dataplane.
@deffn {OSPF Command} {segment-routing on} {}
@deffnx {OSPF Command} {no segment-routing} {}
Enable Segment Routing. Even if this also activate routing information support,
it is preferable to also activate routing information, and set accordingly the
Area or AS flooding.
@end deffn
@deffn {OSPF Command} {segment-routing global-block (0-1048575) (0-1048575)} {}
@deffnx {OSPF Command} {no segment-routing global-block} {}
Fix the Segment Routing Global Block i.e. the label range used by MPLS to store
label in the MPLS FIB.
@end deffn
@deffn {OSPF Command} {segment-routing node-msd (1-16)} {}
@deffnx {OSPF Command} {no segment-routing node-msd} {}
Fix the Maximum Stack Depth supported by the router. The value depend of the
MPLS dataplane. E.g. for Linux kernel, since version 4.13 it is 32.
@end deffn
@deffn {OSPF Command} {segment-routing prefix A.B.C.D/M index (0-65535)} {}
@deffnx {OSPF Command} {no segment-routing prefix A.B.C.D/M} {}
Set the Segment Rounting index for the specifyed prefix. Note
that, only prefix with /32 corresponding to a loopback interface are
currently supported.
@end deffn
@deffn {Command} {show ip ospf database segment-routing} {}
@deffnx {Command} {show ip ospf database segment-routing adv-router @var{adv-router}} {}
@deffnx {Command} {show ip ospf database segment-routing self-originate} {}
Show Segment Routing Data Base, all SR nodes, specific advertized router or self router.
@end deffn
@node Debugging OSPF
@section Debugging OSPF

View File

@ -358,6 +358,7 @@ struct cmd_node {
#define OSPF_RI_STR "OSPF Router Information specific commands\n"
#define PCE_STR "PCE Router Information specific commands\n"
#define MPLS_STR "MPLS information\n"
#define SR_STR "Segment-Routing specific commands\n"
#define WATCHFRR_STR "watchfrr information\n"
#define ZEBRA_STR "Zebra information\n"

View File

@ -41,8 +41,10 @@
#define MPLS_MAX_UNRESERVED_LABEL 1048575
/* Default min and max SRGB label range */
#define MPLS_DEFAULT_MIN_SRGB_LABEL 16000
#define MPLS_DEFAULT_MAX_SRGB_LABEL 23999
#define MPLS_DEFAULT_MIN_SRGB_LABEL 10000
#define MPLS_DEFAULT_MAX_SRGB_LABEL 50000
#define MPLS_DEFAULT_MIN_SRGB_SIZE 5000
#define MPLS_DEFAULT_MAX_SRGB_SIZE 20000
/* Maximum # labels that can be pushed. */
#define MPLS_MAX_LABELS 16
@ -94,7 +96,8 @@ enum lsp_types_t {
ZEBRA_LSP_NONE = 0, /* No LSP. */
ZEBRA_LSP_STATIC = 1, /* Static LSP. */
ZEBRA_LSP_LDP = 2, /* LDP LSP. */
ZEBRA_LSP_BGP = 3 /* BGP LSP. */
ZEBRA_LSP_BGP = 3, /* BGP LSP. */
ZEBRA_LSP_SR = 4 /* Segment Routing LSP. */
};
/* Functions for basic label operations. */

View File

@ -78,6 +78,7 @@ ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL, 'b', 0, 0, "BGP-Direct"
ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, "BGP2VNC"
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
ZEBRA_ROUTE_SHARP, sharp, sharpd, 'D', 1, 1, "SHARP"
ZEBRA_ROUTE_OSPF_SR, ospf-sr, ospfd, 's', 1, 0, "OSPF-SR"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, "-"
@ -103,3 +104,4 @@ ZEBRA_ROUTE_LDP, "Label Distribution Protocol (LDP)"
ZEBRA_ROUTE_VNC_DIRECT, "VNC direct (not via zebra) routes"
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
ZEBRA_ROUTE_SHARP, "Super Happy Advanced Routing Protocol (sharpd)"
ZEBRA_ROUTE_OSPF_SR, "OSPF Segment Routing (OSPF-SR)"

View File

@ -51,6 +51,8 @@ unsigned long conf_debug_ospf_lsa = 0;
unsigned long conf_debug_ospf_zebra = 0;
unsigned long conf_debug_ospf_nssa = 0;
unsigned long conf_debug_ospf_te = 0;
unsigned long conf_debug_ospf_ext = 0;
unsigned long conf_debug_ospf_sr = 0;
/* Enable debug option variables -- valid only session. */
unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@ -61,7 +63,8 @@ unsigned long term_debug_ospf_lsa = 0;
unsigned long term_debug_ospf_zebra = 0;
unsigned long term_debug_ospf_nssa = 0;
unsigned long term_debug_ospf_te = 0;
unsigned long term_debug_ospf_ext = 0;
unsigned long term_debug_ospf_sr = 0;
const char *ospf_redist_string(u_int route_type)
{
@ -1441,6 +1444,33 @@ DEFUN (no_debug_ospf_te,
return CMD_SUCCESS;
}
DEFUN (debug_ospf_sr,
debug_ospf_sr_cmd,
"debug ospf sr",
DEBUG_STR
OSPF_STR
"OSPF-SR information\n")
{
if (vty->node == CONFIG_NODE)
CONF_DEBUG_ON(sr, SR);
TERM_DEBUG_ON(sr, SR);
return CMD_SUCCESS;
}
DEFUN (no_debug_ospf_sr,
no_debug_ospf_sr_cmd,
"no debug ospf sr",
NO_STR
DEBUG_STR
OSPF_STR
"OSPF-SR information\n")
{
if (vty->node == CONFIG_NODE)
CONF_DEBUG_OFF(sr, SR);
TERM_DEBUG_OFF(sr, SR);
return CMD_SUCCESS;
}
DEFUN (no_debug_ospf,
no_debug_ospf_cmd,
"no debug ospf",
@ -1774,6 +1804,7 @@ void debug_init()
install_element(ENABLE_NODE, &debug_ospf_event_cmd);
install_element(ENABLE_NODE, &debug_ospf_nssa_cmd);
install_element(ENABLE_NODE, &debug_ospf_te_cmd);
install_element(ENABLE_NODE, &debug_ospf_sr_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_ism_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_nsm_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_lsa_cmd);
@ -1781,6 +1812,7 @@ void debug_init()
install_element(ENABLE_NODE, &no_debug_ospf_event_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_nssa_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_te_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_sr_cmd);
install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd);
install_element(ENABLE_NODE, &debug_ospf_packet_cmd);
@ -1809,12 +1841,14 @@ void debug_init()
install_element(CONFIG_NODE, &debug_ospf_event_cmd);
install_element(CONFIG_NODE, &debug_ospf_nssa_cmd);
install_element(CONFIG_NODE, &debug_ospf_te_cmd);
install_element(CONFIG_NODE, &debug_ospf_sr_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_nsm_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_lsa_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_zebra_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_event_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_nssa_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_te_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_sr_cmd);
install_element(CONFIG_NODE, &debug_ospf_instance_nsm_cmd);
install_element(CONFIG_NODE, &debug_ospf_instance_lsa_cmd);

View File

@ -57,6 +57,8 @@
#define OSPF_DEBUG_EVENT 0x01
#define OSPF_DEBUG_NSSA 0x02
#define OSPF_DEBUG_TE 0x04
#define OSPF_DEBUG_EXT 0x08
#define OSPF_DEBUG_SR 0x10
/* Macro for setting debug option. */
#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b)
@ -98,6 +100,10 @@
#define IS_DEBUG_OSPF_TE IS_DEBUG_OSPF(te,TE)
#define IS_DEBUG_OSPF_EXT IS_DEBUG_OSPF(ext,EXT)
#define IS_DEBUG_OSPF_SR IS_DEBUG_OSPF(sr,SR)
#define IS_CONF_DEBUG_OSPF_PACKET(a, b) \
(conf_debug_ospf_packet[a] & OSPF_DEBUG_##b)
#define IS_CONF_DEBUG_OSPF(a, b) (conf_debug_ospf_##a & OSPF_DEBUG_##b)
@ -119,6 +125,8 @@ extern unsigned long term_debug_ospf_lsa;
extern unsigned long term_debug_ospf_zebra;
extern unsigned long term_debug_ospf_nssa;
extern unsigned long term_debug_ospf_te;
extern unsigned long term_debug_ospf_ext;
extern unsigned long term_debug_ospf_sr;
/* Message Strings. */
extern char *ospf_lsa_type_str[];

1769
ospfd/ospf_ext.c Normal file

File diff suppressed because it is too large Load Diff

196
ospfd/ospf_ext.h Normal file
View File

@ -0,0 +1,196 @@
/*
* This is an implementation of RFC7684 OSPFv2 Prefix/Link Attribute
* Advertisement
*
* Module name: Extended Prefix/Link Opaque LSA header definition
*
* Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
* Author: Olivier Dugeon <olivier.dugeon@orange.com>
*
* Copyright (C) 2016 - 2017 Orange Labs http://www.orange.com
*
* This file is part of FRR.
*
* FRR is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* FRR is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FRR; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef _FRR_OSPF_EXT_PREF_H_
#define _FRR_OSPF_EXT_PREF_H_
/*
* Opaque LSA's link state ID for Extended Prefix/Link is
* structured as follows.
*
* 24 16 8 0
* +--------+--------+--------+--------+
* | 7/8 |........|........|........|
* +--------+--------+--------+--------+
* |<-Type->|<------- Instance ------->|
*
*
* Type: IANA has assigned '7' for Extended Prefix Opaque LSA
* and '8' for Extended Link Opaque LSA
* Instance: User may select arbitrary 24-bit values to identify
* different instances of Extended Prefix/Link Opaque LSA
*
*/
/*
* 24 16 8 0
* +--------+--------+--------+--------+ ---
* | LS age |Options | 10,11 | A
* +--------+--------+--------+--------+ | Standard (Opaque) LSA header;
* | 7/8 | Instance | |
* +--------+--------+--------+--------+ | Type 10 or 11 are used for Extended
* | Advertising router | | Prefix Opaque LSA
* +--------+--------+--------+--------+ |
* | LS sequence number | | Type 10 only is used for Extended
* +--------+--------+--------+--------+ | Link Opaque LSA
* | LS checksum | Length | V
* +--------+--------+--------+--------+ ---
* | Type | Length | A
* +--------+--------+--------+--------+ | TLV part for Extended Prefix/Link
* | | | Opaque LSA;
* ~ Values ... ~ | Values might be structured as a set
* | | V of sub-TLVs.
* +--------+--------+--------+--------+ ---
*/
/* Global use constant numbers */
#define MAX_LEGAL_EXT_INSTANCE_NUM (0xffff)
#define LEGAL_EXT_INSTANCE_RANGE(i) (0 <= (i) && (i) <= 0xffff)
/* Flags to manage Extended Link/Prefix Opaque LSA */
#define EXT_LPFLG_LSA_INACTIVE 0x00
#define EXT_LPFLG_LSA_ACTIVE 0x01
#define EXT_LPFLG_LSA_ENGAGED 0x02
#define EXT_LPFLG_LSA_LOOKUP_DONE 0x04
#define EXT_LPFLG_LSA_FORCED_REFRESH 0x08
#define EXT_LPFLG_FIB_ENTRY_SET 0x10
/*
* Following section defines TLV (tag, length, value) structures,
* used in Extended Prefix/Link Opaque LSA.
*/
/* Extended Prefix TLV Route Types */
#define EXT_TLV_PREF_ROUTE_UNSPEC 0
#define EXT_TLV_PREF_ROUTE_INTRA_AREA 1
#define EXT_TLV_PREF_ROUTE_INTER_AREA 3
#define EXT_TLV_PREF_ROUTE_AS_EXT 5
#define EXT_TLV_PREF_ROUTE_NSSA_EXT 7
/* Extended Prefix and Extended Prefix Range TLVs'
* Address family flag for IPv4 */
#define EXT_TLV_PREF_AF_IPV4 0
/* Extended Prefix TLV Flags */
#define EXT_TLV_PREF_AFLG 0x80
#define EXT_TLV_PREF_NFLG 0x40
/* Extended Prefix Range TLV Flags */
#define EXT_TLV_PREF_RANGE_IAFLG 0x80
/* ERO subtlvs Flags */
#define EXT_SUBTLV_ERO_LFLG 0x80
/* Extended Prefix TLV see RFC 7684 section 2.1 */
#define EXT_TLV_PREFIX 1
#define EXT_TLV_PREFIX_SIZE 8
struct ext_tlv_prefix {
struct tlv_header header;
u_int8_t route_type;
u_int8_t pref_length;
u_int8_t af;
u_int8_t flags;
struct in_addr address;
};
/* Extended Link TLV see RFC 7684 section 3.1 */
#define EXT_TLV_LINK 1
#define EXT_TLV_LINK_SIZE 12
struct ext_tlv_link {
struct tlv_header header;
u_int8_t link_type;
u_int8_t reserved[3];
struct in_addr link_id;
struct in_addr link_data;
};
/* Remote Interface Address Sub-TLV, Cisco experimental use Sub-TLV */
#define EXT_SUBTLV_RMT_ITF_ADDR 32768
#define EXT_SUBTLV_RMT_ITF_ADDR_SIZE 4
struct ext_subtlv_rmt_itf_addr {
struct tlv_header header;
struct in_addr value;
};
/* Internal structure to manage Extended Link/Prefix Opaque LSA */
struct ospf_ext_lp {
bool enabled;
/* Flags to manage this Extended Prefix/Link Opaque LSA */
u_int32_t flags;
/* Scope is area Opaque Type 10 or AS Opaque LSA Type 11 for
* Extended Prefix and area Opaque Type 10 for Extended Link */
u_int8_t scope;
/* area pointer if flooding is Type 10 Null if flooding is AS scope */
struct ospf_area *area;
struct in_addr area_id;
/* List of interface with Segment Routing enable */
struct list *iflist;
};
/* Structure to aggregate interfaces information for Extended Prefix/Link */
struct ext_itf {
/* 24-bit Opaque-ID field value according to RFC 7684 specification */
u_int32_t instance;
u_int8_t type; /* Extended Prefix (7) or Link (8) */
/* Reference pointer to a Zebra-interface. */
struct interface *ifp;
/* Area info in which this SR link belongs to. */
struct ospf_area *area;
/* Flags to manage this link parameters. */
u_int32_t flags;
/* SID type: Node, Adjacency or LAN Adjacency */
enum sid_type stype;
/* extended link/prefix TLV information */
struct ext_tlv_prefix prefix;
struct ext_subtlv_prefix_sid node_sid;
struct ext_tlv_link link;
struct ext_subtlv_adj_sid adj_sid[2];
struct ext_subtlv_lan_adj_sid lan_sid[2];
/* cisco experimental subtlv */
struct ext_subtlv_rmt_itf_addr rmt_itf_addr;
};
/* Prototypes. */
extern int ospf_ext_init(void);
extern void ospf_ext_term(void);
extern void ospf_ext_update_sr(bool);
extern int ospf_ext_schedule_prefix_index(struct interface *, u_int32_t,
struct prefix_ipv4 *);
#endif /* _FRR_OSPF_EXT_PREF_H_ */

View File

@ -53,3 +53,5 @@ DEFINE_MTYPE(OSPFD, OSPF_IF_PARAMS, "OSPF if params")
DEFINE_MTYPE(OSPFD, OSPF_MESSAGE, "OSPF message")
DEFINE_MTYPE(OSPFD, OSPF_MPLS_TE, "OSPF MPLS parameters")
DEFINE_MTYPE(OSPFD, OSPF_PCE_PARAMS, "OSPF PCE parameters")
DEFINE_MTYPE(OSPFD, OSPF_EXT_PARAMS, "OSPF Extended parameters")
DEFINE_MTYPE(OSPFD, OSPF_SR_PARAMS, "OSPF Segment Routing parameters")

View File

@ -52,5 +52,7 @@ DECLARE_MTYPE(OSPF_IF_PARAMS)
DECLARE_MTYPE(OSPF_MESSAGE)
DECLARE_MTYPE(OSPF_MPLS_TE)
DECLARE_MTYPE(OSPF_PCE_PARAMS)
DECLARE_MTYPE(OSPF_SR_PARAMS)
DECLARE_MTYPE(OSPF_EXT_PARAMS)
#endif /* _QUAGGA_OSPF_MEMORY_H */

View File

@ -50,6 +50,10 @@
#include "ospfd/ospf_route.h"
#include "ospfd/ospf_ase.h"
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_te.h"
#include "ospfd/ospf_sr.h"
#include "ospfd/ospf_ri.h"
#include "ospfd/ospf_ext.h"
DEFINE_MTYPE_STATIC(OSPFD, OSPF_OPAQUE_FUNCTAB, "OSPF opaque function table")
DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_TYPE, "OSPF opaque per-type info")
@ -59,9 +63,6 @@ DEFINE_MTYPE_STATIC(OSPFD, OPAQUE_INFO_PER_ID, "OSPF opaque per-ID info")
* Followings are initialize/terminate functions for Opaque-LSAs handling.
*------------------------------------------------------------------------*/
#include "ospfd/ospf_te.h"
#include "ospfd/ospf_ri.h"
#ifdef SUPPORT_OSPF_API
int ospf_apiserver_init(void);
void ospf_apiserver_term(void);
@ -85,9 +86,17 @@ void ospf_opaque_init(void)
if (ospf_mpls_te_init() != 0)
exit(1);
/* Segment Routing init */
if (ospf_sr_init() != 0)
exit(1);
if (ospf_router_info_init() != 0)
exit(1);
/* Force Extended Prefix/Link to Type 10 */
if (ospf_ext_init() != 0)
exit(1);
#ifdef SUPPORT_OSPF_API
if ((ospf_apiserver_enable) && (ospf_apiserver_init() != 0))
exit(1);
@ -102,6 +111,10 @@ void ospf_opaque_term(void)
ospf_router_info_term();
ospf_ext_term();
ospf_sr_term();
#ifdef SUPPORT_OSPF_API
ospf_apiserver_term();
#endif /* SUPPORT_OSPF_API */
@ -209,6 +222,12 @@ static const char *ospf_opaque_type_name(u_char opaque_type)
case OPAQUE_TYPE_ROUTER_INFORMATION_LSA:
name = "Router Information LSA";
break;
case OPAQUE_TYPE_EXTENDED_PREFIX_LSA:
name = "Extended Prefix Opaque LSA";
break;
case OPAQUE_TYPE_EXTENDED_LINK_LSA:
name = "Extended Link Opaque LSA";
break;
default:
if (OPAQUE_TYPE_RANGE_UNASSIGNED(opaque_type))
name = "Unassigned";

View File

@ -59,7 +59,9 @@
#define OPAQUE_TYPE_L1VPN_LSA 5
#define OPAQUE_TYPE_ROUTER_INFORMATION_LSA 4
#define OPAQUE_TYPE_INTER_AS_LSA 6
#define OPAQUE_TYPE_MAX 6
#define OPAQUE_TYPE_EXTENDED_PREFIX_LSA 7
#define OPAQUE_TYPE_EXTENDED_LINK_LSA 8
#define OPAQUE_TYPE_MAX 8
/* Followings types are proposed in internet-draft documents. */
#define OPAQUE_TYPE_8021_QOSPF 129

View File

@ -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.enabled)
return;
if (OspfRI.pce_info.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 (pce->pce_address.header.type != 0)
vty_out(vty, " pce address %s\n",
inet_ntoa(pce->pce_address.address.value));
if (OspfRI.pce_info.enabled) {
if (pce->pce_cap_flag.header.type != 0)
vty_out(vty, " pce flag 0x%x\n",
ntohl(pce->pce_cap_flag.value));
if (pce->pce_address.header.type != 0)
vty_out(vty, " pce address %s\n",
inet_ntoa(pce->pce_address.address.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 (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));
}
}
}
if (pce->pce_scope.header.type != 0)
vty_out(vty, " pce scope 0x%x\n",
ntohl(OspfRI.pce_info.pce_scope.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));
}
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;

View File

@ -1,11 +1,13 @@
/*
* This is an implementation of RFC4970 Router Information
* with support of RFC5088 PCE Capabilites announcement
* and support of draft-ietf-ospf-segment-routing-extensions-18
* for Segment Routing Capabilities 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 Zebra.
*
@ -33,7 +35,7 @@
*
* 24 16 8 0
* +--------+--------+--------+--------+
* | 1 | MBZ |........|........|
* | 4 | MBZ |........|........|
* +--------+--------+--------+--------+
* |<-Type->|<Resv'd>|<-- Instance --->|
*
@ -57,9 +59,8 @@
* +--------+--------+--------+--------+ |
* | LS checksum | Length | V
* +--------+--------+--------+--------+ ---
* | Type | Length | A
* +--------+--------+--------+--------+ | TLV part for Router Information;
* Values might be
* | Type | Length | A TLV part for Router Information;
* +--------+--------+--------+--------+ | Values might be
* | Values ... | V structured as a set of sub-TLVs.
* +--------+--------+--------+--------+ ---
*/
@ -68,9 +69,9 @@
* Following section defines TLV body parts.
*/
/* Up to now, 8 code point have been assigned to Router Information */
/* Up to now, 11 code points have been assigned to Router Information */
/* Only type 1 Router Capabilities and 6 PCE are supported with this code */
#define RI_IANA_MAX_TYPE 8
#define RI_IANA_MAX_TYPE 11
/* RFC4970: Router Information Capabilities TLV */ /* Mandatory */
#define RI_TLV_CAPABILITIES 1
@ -80,12 +81,13 @@ struct ri_tlv_router_cap {
u_int32_t value;
};
#define RI_GRACE_RESTART 0x01
#define RI_GRACE_HELPER 0x02
#define RI_STUB_SUPPORT 0x04
#define RI_TE_SUPPORT 0x08
#define RI_P2P_OVER_LAN 0x10
#define RI_TE_EXPERIMENTAL 0x20
/* Capabilities bits are left align */
#define RI_GRACE_RESTART 0x80000000
#define RI_GRACE_HELPER 0x40000000
#define RI_STUB_SUPPORT 0x20000000
#define RI_TE_SUPPORT 0x10000000
#define RI_P2P_OVER_LAN 0x08000000
#define RI_TE_EXPERIMENTAL 0x04000000
#define RI_TLV_LENGTH 4
@ -151,22 +153,30 @@ struct ri_pce_subtlv_neighbor {
#define RI_PCE_SUBTLV_CAP_FLAG 5
#define PCE_CAP_GMPLS_LINK 0x0001
#define PCE_CAP_BIDIRECTIONAL 0x0002
#define PCE_CAP_DIVERSE_PATH 0x0004
#define PCE_CAP_LOAD_BALANCE 0x0008
#define PCE_CAP_SYNCHRONIZED 0x0010
#define PCE_CAP_BIDIRECTIONAL 0x0002
#define PCE_CAP_DIVERSE_PATH 0x0004
#define PCE_CAP_LOAD_BALANCE 0x0008
#define PCE_CAP_SYNCHRONIZED 0x0010
#define PCE_CAP_OBJECTIVES 0x0020
#define PCE_CAP_ADDITIVE 0x0040
#define PCE_CAP_PRIORIZATION 0x0080
#define PCE_CAP_MULTIPLE_REQ 0x0100
#define PCE_CAP_PRIORIZATION 0x0080
#define PCE_CAP_MULTIPLE_REQ 0x0100
struct ri_pce_subtlv_cap_flag {
struct tlv_header header; /* Type = 5; Length = n x 4 bytes. */
u_int32_t value;
};
/* Structure to share flooding scope info for Segment Routing */
struct scope_info {
u_int8_t scope;
struct in_addr area_id;
};
/* Prototypes. */
extern int ospf_router_info_init(void);
extern void ospf_router_info_term(void);
extern int ospf_router_info_enable(void);
extern void ospf_router_info_update_sr(bool, struct sr_srgb, u_int8_t);
extern struct scope_info ospf_router_info_get_flooding_scope(void);
#endif /* _ZEBRA_OSPF_ROUTER_INFO_H */

View File

@ -46,6 +46,7 @@
#include "ospfd/ospf_ase.h"
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_sr.h"
/* Variables to ensure a SPF scheduled log message is printed only once */
@ -1339,7 +1340,6 @@ static int ospf_spf_calculate_timer(struct thread *thread)
ospf_ase_calculate_timer_add(ospf);
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("%s: ospf install new route, vrf %s id %u new_table count %lu",
__PRETTY_FUNCTION__,
@ -1366,6 +1366,9 @@ static int ospf_spf_calculate_timer(struct thread *thread)
ospf_abr_task(ospf);
abr_time = monotime_since(&start_time, NULL);
/* Schedule Segment Routing update */
ospf_sr_update_timer_add(ospf);
total_spf_time =
monotime_since(&spf_start_time, &ospf->ts_spf_duration);

2186
ospfd/ospf_sr.c Normal file

File diff suppressed because it is too large Load Diff

315
ospfd/ospf_sr.h Normal file
View File

@ -0,0 +1,315 @@
/*
* This is an implementation of Segment Routing
* as per draft draft-ietf-ospf-segment-routing-extensions-24
*
* Module name: Segment Routing header definitions
*
* Author: Olivier Dugeon <olivier.dugeon@orange.com>
* Author: Anselme Sawadogo <anselmesawadogo@gmail.com>
*
* Copyright (C) 2016 - 2017 Orange Labs http://www.orange.com
*
* This file is part of FRR.
*
* FRR is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
*
* FRR is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with FRR; see the file COPYING. If not, write to the Free
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#ifndef _FRR_OSPF_SR_H
#define _FRR_OSPF_SR_H
/* Default Route priority for OSPF Segment Routing */
#define OSPF_SR_PRIORITY_DEFAULT 10
/* macros and constants for segment routing */
#define SET_RANGE_SIZE_MASK 0xffffff00
#define GET_RANGE_SIZE_MASK 0x00ffffff
#define SET_LABEL_MASK 0xffffff00
#define GET_LABEL_MASK 0x00ffffff
#define SET_RANGE_SIZE(range_size) ((range_size << 8) & SET_RANGE_SIZE_MASK)
#define GET_RANGE_SIZE(range_size) ((range_size >> 8) & GET_RANGE_SIZE_MASK)
#define SET_LABEL(label) ((label << 8) & SET_LABEL_MASK)
#define GET_LABEL(label) ((label >> 8) & GET_LABEL_MASK)
/* Label range for Adj-SID attribution purpose. See ospf_ext.c */
#define ADJ_SID_MIN 50000
#define ADJ_SID_MAX 51000
#define OSPF_SR_DEFAULT_METRIC 1
/* Segment Routing TLVs as per draft-ietf-ospf-segment-routing-extensions-19 */
/* Segment ID could be a Label (3 bytes) or an Index (4 bytes) */
#define SID_BASE_SIZE 4
#define SID_LABEL 3
#define SID_LABEL_SIZE (SID_BASE_SIZE + SID_LABEL)
#define SID_INDEX 4
#define SID_INDEX_SIZE (SID_BASE_SIZE + SID_INDEX)
/* SID/Label Sub TLV - section 2.1 */
#define SUBTLV_SID_LABEL 1
#define SUBTLV_SID_LABEL_SIZE 8
struct subtlv_sid_label {
/* Length is 3 (20 rightmost bits MPLS label) or 4 (32 bits SID) */
struct tlv_header header;
u_int32_t value;
};
/*
* Following section defines Segment Routing TLV (tag, length, value)
* structures, used in Router Information Opaque LSA.
*/
/* RI SR-Algorithm TLV - section 3.1 */
#define RI_SR_TLV_SR_ALGORITHM 8
struct ri_sr_tlv_sr_algorithm {
struct tlv_header header;
#define SR_ALGORITHM_SPF 0
#define SR_ALGORITHM_STRICT_SPF 1
#define SR_ALGORITHM_UNSET 255
#define ALGORITHM_COUNT 4
/* Only 4 algorithms supported in this code */
u_int8_t value[ALGORITHM_COUNT];
};
/* RI SID/Label Range TLV - section 3.2 */
#define RI_SR_TLV_SID_LABEL_RANGE 9
struct ri_sr_tlv_sid_label_range {
struct tlv_header header;
/* Only 24 upper most bits are significant */
#define SID_RANGE_LABEL_LENGTH 3
u_int32_t size;
/* A SID/Label sub-TLV will follow. */
struct subtlv_sid_label lower;
};
/* RI Node/MSD TLV as per draft-ietf-ospf-segment-routing-msd-05 */
#define RI_SR_TLV_NODE_MSD 12
struct ri_sr_tlv_node_msd {
struct tlv_header header;
u_int8_t subtype; /* always = 1 */
u_int8_t value;
u_int16_t padding;
};
/*
* Following section defines Segment Routing TLV (tag, length, value)
* structures, used in Extended Prefix/Link Opaque LSA.
*/
/* Adj-SID and LAN-Ajd-SID subtlvs' flags */
#define EXT_SUBTLV_LINK_ADJ_SID_BFLG 0x80
#define EXT_SUBTLV_LINK_ADJ_SID_VFLG 0x40
#define EXT_SUBTLV_LINK_ADJ_SID_LFLG 0x20
#define EXT_SUBTLV_LINK_ADJ_SID_SFLG 0x10
/* Prefix SID subtlv Flags */
#define EXT_SUBTLV_PREFIX_SID_NPFLG 0x40
#define EXT_SUBTLV_PREFIX_SID_MFLG 0x20
#define EXT_SUBTLV_PREFIX_SID_EFLG 0x10
#define EXT_SUBTLV_PREFIX_SID_VFLG 0x08
#define EXT_SUBTLV_PREFIX_SID_LFLG 0x04
/* SID/Label Binding subtlv Flags */
#define EXT_SUBTLV_SID_BINDING_MFLG 0x80
/* Extended Prefix Range TLV - section 4 */
#define EXT_TLV_PREF_RANGE 2
#define EXT_SUBTLV_PREFIX_RANGE_SIZE 12
struct ext_tlv_prefix_range {
struct tlv_header header;
u_int8_t pref_length;
u_int8_t af;
u_int16_t range_size;
u_int8_t flags;
u_int8_t reserved[3];
struct in_addr address;
};
/* Prefix SID Sub-TLV - section 5 */
#define EXT_SUBTLV_PREFIX_SID 2
#define EXT_SUBTLV_PREFIX_SID_SIZE 8
struct ext_subtlv_prefix_sid {
struct tlv_header header;
u_int8_t flags;
u_int8_t reserved;
u_int8_t mtid;
u_int8_t algorithm;
u_int32_t value;
};
/* Adj-SID Sub-TLV - section 6.1 */
#define EXT_SUBTLV_ADJ_SID 2
#define EXT_SUBTLV_ADJ_SID_SIZE 8
struct ext_subtlv_adj_sid {
struct tlv_header header;
u_int8_t flags;
u_int8_t reserved;
u_int8_t mtid;
u_int8_t weight;
u_int32_t value;
};
/* LAN Adj-SID Sub-TLV - section 6.2 */
#define EXT_SUBTLV_LAN_ADJ_SID 3
#define EXT_SUBTLV_LAN_ADJ_SID_SIZE 12
struct ext_subtlv_lan_adj_sid {
struct tlv_header header;
u_int8_t flags;
u_int8_t reserved;
u_int8_t mtid;
u_int8_t weight;
struct in_addr neighbor_id;
u_int32_t value;
};
/*
* Following section define structure used to manage Segment Routing
* information and TLVs / SubTLVs
*/
/* Structure aggregating SRGB info retrieved from an lsa */
struct sr_srgb {
u_int32_t range_size;
u_int32_t lower_bound;
};
/* SID type to make difference between loopback interfaces and others */
enum sid_type { PREF_SID, ADJ_SID, LAN_ADJ_SID };
/* Structure aggregating all OSPF Segment Routing information for the node */
struct ospf_sr_db {
/* Status of Segment Routing: enable or disable */
bool enabled;
/* Ongoing Update following an OSPF SPF */
bool update;
/* Flooding Scope: Area = 10 or AS = 11 */
u_int8_t scope;
/* FRR SR node */
struct sr_node *self;
/* List of neighbour SR nodes */
struct hash *neighbors;
/* List of SR prefix */
struct route_table *prefix;
/* Local SR info announced in Router Info LSA */
/* Algorithms supported by the node */
u_int8_t algo[ALGORITHM_COUNT];
/*
* Segment Routing Global Block i.e. label range
* Only one range supported in this code
*/
struct sr_srgb srgb;
/* Maximum SID Depth supported by the node */
u_int8_t msd;
};
/* Structure aggregating all received SR info from LSAs by node */
struct sr_node {
struct in_addr adv_router; /* used to identify sender of LSA */
/* 24-bit Opaque-ID field value according to RFC 7684 specification */
u_int32_t instance;
u_int8_t algo[ALGORITHM_COUNT]; /* Algorithms supported by the node */
/* Segment Routing Global Block i.e. label range */
struct sr_srgb srgb;
u_int8_t msd; /* Maximum SID Depth */
/* List of Prefix & Link advertise by this node */
struct list *ext_prefix; /* For Node SID */
struct list *ext_link; /* For Adj and LAN SID */
/* Pointer to FRR SR-Node or NULL if it is not a neighbor */
struct sr_node *neighbor;
};
/* Segment Routing - NHLFE info: support IPv4 Only */
struct sr_nhlfe {
struct prefix_ipv4 prefv4;
struct in_addr nexthop;
ifindex_t ifindex;
mpls_label_t label_in;
mpls_label_t label_out;
};
/* Structure aggregating all Segment Routing Link information */
/* Link are generally advertised by pair: primary + backup */
struct sr_link {
struct in_addr adv_router; /* used to identify sender of LSA */
/* 24-bit Opaque-ID field value according to RFC 7684 specification */
u_int32_t instance;
/* Flags to manage this link parameters. */
u_int32_t flags[2];
/* Segment Routing ID */
u_int32_t sid[2];
enum sid_type type;
/* SR NHLFE for this link */
struct sr_nhlfe nhlfe[2];
/* Back pointer to SR Node which advertise this Link */
struct sr_node *srn;
};
/* Structure aggregating all Segment Routing Prefix information */
struct sr_prefix {
struct in_addr adv_router; /* used to identify sender of LSA */
/* 24-bit Opaque-ID field value according to RFC 7684 specification */
u_int32_t instance;
/* Flags to manage this prefix parameters. */
u_int32_t flags;
/* Segment Routing ID */
u_int32_t sid;
enum sid_type type;
/* SR NHLFE for this prefix */
struct sr_nhlfe nhlfe;
/* Back pointer to SR Node which advertise this Prefix */
struct sr_node *srn;
/* Pointer to SR Node which is the next hop for this Prefix
* or NULL if next hop is the destination of the prefix */
struct sr_node *nexthop;
};
/* Prototypes definition */
/* Segment Routing initialisation functions */
extern int ospf_sr_init(void);
extern void ospf_sr_term(void);
/* Segment Routing LSA update & delete functions */
extern void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa);
extern void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa);
extern void ospf_sr_ext_link_lsa_update(struct ospf_lsa *);
extern void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *);
extern void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *);
extern void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *);
/* Segment Routing configuration functions */
extern u_int32_t get_ext_link_label_value(void);
extern void ospf_sr_config_write_router(struct vty *);
/* Segment Routing re-routing function */
extern void ospf_sr_update_timer_add(struct ospf *);
#endif /* _FRR_OSPF_SR_H */

View File

@ -240,6 +240,7 @@ struct ospf {
struct thread *t_external_lsa; /* AS-external-LSA origin timer. */
struct thread
*t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */
struct thread *t_sr_update; /* Segment Routing update timer */
unsigned int maxage_delay; /* Delay on Maxage remover timer, sec */
struct thread *t_maxage; /* MaxAge LSA remover timer. */

View File

@ -20,6 +20,7 @@ ospfd_libfrrospf_a_SOURCES = \
ospfd/ospf_bfd.c \
ospfd/ospf_dump.c \
ospfd/ospf_dump_api.c \
ospfd/ospf_ext.c \
ospfd/ospf_flood.c \
ospfd/ospf_ia.c \
ospfd/ospf_interface.c \
@ -36,6 +37,7 @@ ospfd_libfrrospf_a_SOURCES = \
ospfd/ospf_route.c \
ospfd/ospf_routemap.c \
ospfd/ospf_spf.c \
ospfd/ospf_sr.c \
ospfd/ospf_te.c \
ospfd/ospf_vty.c \
ospfd/ospf_zebra.c \
@ -66,6 +68,7 @@ noinst_HEADERS += \
ospfd/ospf_apiserver.h \
ospfd/ospf_ase.h \
ospfd/ospf_bfd.h \
ospfd/ospf_ext.h \
ospfd/ospf_flood.h \
ospfd/ospf_ia.h \
ospfd/ospf_interface.h \
@ -76,6 +79,7 @@ noinst_HEADERS += \
ospfd/ospf_ri.h \
ospfd/ospf_route.h \
ospfd/ospf_spf.h \
ospfd/ospf_sr.h \
ospfd/ospf_te.h \
ospfd/ospf_vty.h \
ospfd/ospf_zebra.h \

View File

@ -75,6 +75,7 @@ vtysh_scan += $(top_srcdir)/ospfd/ospf_opaque.c
vtysh_scan += $(top_srcdir)/ospfd/ospf_ri.c
vtysh_scan += $(top_srcdir)/ospfd/ospf_routemap.c
vtysh_scan += $(top_srcdir)/ospfd/ospf_te.c
vtysh_scan += $(top_srcdir)/ospfd/ospf_sr.c
vtysh_scan += $(top_srcdir)/ospfd/ospf_vty.c
endif

View File

@ -102,6 +102,7 @@ static const struct message rtproto_str[] = {
{RTPROT_MROUTED, "mroute"},
{RTPROT_BGP, "BGP"},
{RTPROT_OSPF, "OSPF"},
{RTPROT_OSPF_SR, "OSPF-SR"},
{RTPROT_ISIS, "IS-IS"},
{RTPROT_RIP, "RIP"},
{RTPROT_RIPNG, "RIPNG"},

View File

@ -98,7 +98,8 @@ static inline int is_selfroute(int proto)
|| (proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG)
|| (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP)
|| (proto == RTPROT_LDP) || (proto == RTPROT_BABEL)
|| (proto == RTPROT_RIP) || (proto == RTPROT_SHARP)) {
|| (proto == RTPROT_RIP) || (proto == RTPROT_SHARP)
|| (proto == RTPROT_OSPF_SR)) {
return 1;
}
@ -118,6 +119,9 @@ static inline int zebra2proto(int proto)
case ZEBRA_ROUTE_OSPF6:
proto = RTPROT_OSPF;
break;
case ZEBRA_ROUTE_OSPF_SR:
proto = RTPROT_OSPF_SR;
break;
case ZEBRA_ROUTE_STATIC:
proto = RTPROT_STATIC;
break;

View File

@ -52,6 +52,7 @@
#define RTPROT_EIGRP 192
#define RTPROT_LDP 193
#define RTPROT_SHARP 194
#define RTPROT_OSPF_SR 195
void rt_netlink_init(void);

View File

@ -316,6 +316,12 @@ void mpls_ldp_lsp_uninstall_all(struct hash_backet *backet, void *ctxt);
*/
void mpls_ldp_ftn_uninstall_all(struct zebra_vrf *zvrf, int afi);
/*
* Uninstall all Segment Routing NHLFEs for a particular LSP forwarding entry.
* If no other NHLFEs exist, the entry would be deleted.
*/
void mpls_sr_lsp_uninstall_all(struct hash_backet *backet, void *ctxt);
#if defined(HAVE_CUMULUS)
/*
* Check that the label values used in LSP creation are consistent. The
@ -448,6 +454,8 @@ static inline int re_type_from_lsp_type(enum lsp_types_t lsp_type)
return ZEBRA_ROUTE_LDP;
case ZEBRA_LSP_BGP:
return ZEBRA_ROUTE_BGP;
case ZEBRA_LSP_SR:
return ZEBRA_ROUTE_OSPF_SR;
case ZEBRA_LSP_NONE:
default:
return ZEBRA_ROUTE_KERNEL;
@ -464,6 +472,8 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type)
return "LDP";
case ZEBRA_LSP_BGP:
return "BGP";
case ZEBRA_LSP_SR:
return "SR";
default:
return "Unknown";
}