Skip to content

Commit

Permalink
ospfd: Configurable interface-level 'capability opaque' support
Browse files Browse the repository at this point in the history
    Add support for "[no] ip ospf capbility opaque" at the interface
    level with the default being capability opaque enabled. The command
    "no ip ospf capability opaque" will disable opaque LSA database
    exchange and flooding on the interface. A change in configuration
    will result in the interface being flapped to update our options
    for neighbors but no attempt will be made to purge existing LSAs
    as in dense topologies, these may received by neighbors through
    different interfaces.

    Topotests are added to test both the configuration and the LSA
    opaque flooding suppression.

Signed-off-by: Acee <aceelindem@gmail.com>
  • Loading branch information
Acee committed Jun 20, 2023
1 parent f34076d commit 219386d
Show file tree
Hide file tree
Showing 10 changed files with 498 additions and 25 deletions.
14 changes: 13 additions & 1 deletion doc/user/ospfd.rst
Original file line number Diff line number Diff line change
Expand Up @@ -912,14 +912,26 @@ Opaque LSA



*ospfd* supports Opaque LSA (:rfc:`2370`) as partial support for
*ospfd* supports Opaque LSA (:rfc:`5250`) as partial support for
MPLS Traffic Engineering LSAs. The opaque-lsa capability must be
enabled in the configuration. An alternate command could be
"mpls-te on" (:ref:`ospf-traffic-engineering`). Note that FRR
offers only partial support for some of the routing protocol
extensions that are used with MPLS-TE; it does not support a
complete RSVP-TE solution.

.. clicmd:: ip ospf capability opaque [A.B.C.D]

Enable or disable OSPF LSA database exchange and flooding on an interface.
The default is that opaque capability is enabled as long as the opaque
capability is enabled with the :clicmd:`capability opaque` command at the
OSPF instance level (using the command above). Note that disabling opaque
LSA support on an interface will impact the applications using opaque LSAs
if the opaque LSAs are not received on other flooding paths by all the
OSPF routers using those applications. For example, OSPF Graceful Restart
uses opaque-link LSAs and disabling support on an interface will disable
graceful restart signaling on that interface.

.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external)

.. clicmd:: show ip ospf [vrf <NAME|all>] database (opaque-link|opaque-area|opaque-external) LINK-STATE-ID
Expand Down
1 change: 1 addition & 0 deletions lib/libospf.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ extern "C" {
#define OSPF_MTU_IGNORE_DEFAULT 0
#define OSPF_FAST_HELLO_DEFAULT 0
#define OSPF_P2MP_DELAY_REFLOOD_DEFAULT false
#define OSPF_OPAQUE_CAPABLE_DEFAULT true

#define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */
#define OSPF_AREA_RANGE_COST_UNSPEC -1U
Expand Down
9 changes: 9 additions & 0 deletions ospfd/ospf_flood.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,15 @@ int ospf_flood_through_interface(struct ospf_interface *oi,
if (!ospf_if_is_enable(oi))
return 0;

if (IS_OPAQUE_LSA(lsa->data->type) &&
!OSPF_IF_PARAM(oi, opaque_capable)) {
if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
zlog_debug(
"%s: Skipping interface %s (%s) with opaque disabled.",
__func__, IF_NAME(oi), ospf_get_name(oi->ospf));
return 0;
}

/* If flood reduction is configured, set the DC bit on the lsa. */
if (IS_LSA_SELF(lsa)) {
if (OSPF_FR_CONFIG(oi->area->ospf, oi->area)) {
Expand Down
11 changes: 9 additions & 2 deletions ospfd/ospf_gr.c
Original file line number Diff line number Diff line change
Expand Up @@ -773,8 +773,15 @@ static void ospf_gr_prepare(void)
}

/* Send a Grace-LSA to all neighbors. */
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi))
ospf_gr_lsa_originate(oi, OSPF_GR_SW_RESTART, false);
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi)) {
if (OSPF_IF_PARAM(oi, opaque_capable))
ospf_gr_lsa_originate(oi, OSPF_GR_SW_RESTART,
false);
else
zlog_debug(
"GR: skipping grace LSA on interface %s (%s) with opaque capability disabled",
IF_NAME(oi), ospf_get_name(oi->ospf));
}

/* Record end of the grace period in non-volatile memory. */
ospf_gr_nvm_update(ospf, true);
Expand Down
32 changes: 19 additions & 13 deletions ospfd/ospf_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ static struct ospf_if_params *ospf_new_if_params(void)
UNSET_IF_PARAM(oip, auth_crypt);
UNSET_IF_PARAM(oip, auth_type);
UNSET_IF_PARAM(oip, if_area);
UNSET_IF_PARAM(oip, opaque_capable);

oip->auth_crypt = list_new();

Expand All @@ -546,6 +547,7 @@ static struct ospf_if_params *ospf_new_if_params(void)

oip->ptp_dmvpn = 0;
oip->p2mp_delay_reflood = OSPF_P2MP_DELAY_REFLOOD_DEFAULT;
oip->opaque_capable = OSPF_OPAQUE_CAPABLE_DEFAULT;

return oip;
}
Expand Down Expand Up @@ -575,19 +577,20 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr)
oip = rn->info;
route_unlock_node(rn);

if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd)
&& !OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay)
&& !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval)
&& !OSPF_IF_PARAM_CONFIGURED(oip, passive_interface)
&& !OSPF_IF_PARAM_CONFIGURED(oip, v_hello)
&& !OSPF_IF_PARAM_CONFIGURED(oip, fast_hello)
&& !OSPF_IF_PARAM_CONFIGURED(oip, v_wait)
&& !OSPF_IF_PARAM_CONFIGURED(oip, priority)
&& !OSPF_IF_PARAM_CONFIGURED(oip, type)
&& !OSPF_IF_PARAM_CONFIGURED(oip, auth_simple)
&& !OSPF_IF_PARAM_CONFIGURED(oip, auth_type)
&& !OSPF_IF_PARAM_CONFIGURED(oip, if_area)
&& listcount(oip->auth_crypt) == 0) {
if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd) &&
!OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay) &&
!OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval) &&
!OSPF_IF_PARAM_CONFIGURED(oip, passive_interface) &&
!OSPF_IF_PARAM_CONFIGURED(oip, v_hello) &&
!OSPF_IF_PARAM_CONFIGURED(oip, fast_hello) &&
!OSPF_IF_PARAM_CONFIGURED(oip, v_wait) &&
!OSPF_IF_PARAM_CONFIGURED(oip, priority) &&
!OSPF_IF_PARAM_CONFIGURED(oip, type) &&
!OSPF_IF_PARAM_CONFIGURED(oip, auth_simple) &&
!OSPF_IF_PARAM_CONFIGURED(oip, auth_type) &&
!OSPF_IF_PARAM_CONFIGURED(oip, if_area) &&
!OSPF_IF_PARAM_CONFIGURED(oip, opaque_capable) &&
listcount(oip->auth_crypt) == 0) {
ospf_del_if_params(ifp, oip);
rn->info = NULL;
route_unlock_node(rn);
Expand Down Expand Up @@ -693,6 +696,9 @@ int ospf_if_new_hook(struct interface *ifp)
SET_IF_PARAM(IF_DEF_PARAMS(ifp), auth_type);
IF_DEF_PARAMS(ifp)->auth_type = OSPF_AUTH_NOTSET;

SET_IF_PARAM(IF_DEF_PARAMS(ifp), opaque_capable);
IF_DEF_PARAMS(ifp)->opaque_capable = OSPF_OPAQUE_CAPABLE_DEFAULT;

rc = ospf_opaque_new_if(ifp);
return rc;
}
Expand Down
3 changes: 3 additions & 0 deletions ospfd/ospf_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ struct ospf_if_params {

/* point-to-multipoint delayed reflooding configuration */
bool p2mp_delay_reflood;

/* Opaque LSA capability at interface level (see RFC5250) */
DECLARE_IF_PARAM(bool, opaque_capable);
};

enum { MEMBER_ALLROUTERS = 0,
Expand Down
6 changes: 3 additions & 3 deletions ospfd/ospf_opaque.c
Original file line number Diff line number Diff line change
Expand Up @@ -1851,9 +1851,9 @@ static void ospf_opaque_type9_lsa_reoriginate_timer(struct event *t)
return;
}

if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE)
|| !ospf_if_is_enable(oi)
|| ospf_nbr_count_opaque_capable(oi) == 0) {
if (!CHECK_FLAG(top->config, OSPF_OPAQUE_CAPABLE) ||
!OSPF_IF_PARAM(oi, opaque_capable) || !ospf_if_is_enable(oi) ||
ospf_nbr_count_opaque_capable(oi) == 0) {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"Suspend re-origination of Type-9 Opaque-LSAs (opaque-type=%u) for a while...",
Expand Down
16 changes: 10 additions & 6 deletions ospfd/ospf_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -953,8 +953,9 @@ static void ospf_hello(struct ip *iph, struct ospf_header *ospfh,
}
#endif /* REJECT_IF_TBIT_ON */

if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)
&& CHECK_FLAG(hello->options, OSPF_OPTION_O)) {
if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) &&
OSPF_IF_PARAM(oi, opaque_capable) &&
CHECK_FLAG(hello->options, OSPF_OPTION_O)) {
/*
* This router does know the correct usage of O-bit
* the bit should be set in DD packet only.
Expand Down Expand Up @@ -1362,8 +1363,9 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh,
}
#endif /* REJECT_IF_TBIT_ON */

if (CHECK_FLAG(dd->options, OSPF_OPTION_O)
&& !CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)) {
if (CHECK_FLAG(dd->options, OSPF_OPTION_O) &&
(!CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) ||
!OSPF_IF_PARAM(oi, opaque_capable))) {
/*
* This node is not configured to handle O-bit, for now.
* Clear it to ignore unsupported capability proposed by
Expand Down Expand Up @@ -1448,7 +1450,8 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh,
/* This is where the real Options are saved */
nbr->options = dd->options;

if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE)) {
if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) &&
OSPF_IF_PARAM(oi, opaque_capable)) {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"Neighbor[%pI4] is %sOpaque-capable.",
Expand Down Expand Up @@ -3435,7 +3438,8 @@ static int ospf_make_db_desc(struct ospf_interface *oi,

/* Set Options. */
options = OPTIONS(oi);
if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE))
if (CHECK_FLAG(oi->ospf->config, OSPF_OPAQUE_CAPABLE) &&
OSPF_IF_PARAM(oi, opaque_capable))
SET_FLAG(options, OSPF_OPTION_O);
if (OSPF_FR_CONFIG(oi->ospf, oi->area))
SET_FLAG(options, OSPF_OPTION_DC);
Expand Down
77 changes: 77 additions & 0 deletions ospfd/ospf_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -3810,6 +3810,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
lookup_msg(ospf_ism_state_msg,
oi->state, NULL));
json_object_int_add(json_oi, "priority", PRIORITY(oi));
json_object_boolean_add(
json_interface_sub, "opaqueCapable",
OSPF_IF_PARAM(oi, opaque_capable));
} else {
vty_out(vty, " Area %s\n",
ospf_area_desc_string(oi->area));
Expand All @@ -3829,6 +3832,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
OSPF_IF_PARAM(oi, transmit_delay),
lookup_msg(ospf_ism_state_msg, oi->state, NULL),
PRIORITY(oi));
if (!OSPF_IF_PARAM(oi, opaque_capable))
vty_out(vty,
" Opaque LSA capability disabled on interface\n");
}

/* Show DR information. */
Expand Down Expand Up @@ -9799,6 +9805,59 @@ DEFUN (no_ip_ospf_mtu_ignore,
return CMD_SUCCESS;
}

DEFPY(ip_ospf_capability_opaque, ip_ospf_capability_opaque_addr_cmd,
"[no] ip ospf capability opaque [A.B.C.D]$ip_addr",
NO_STR
"IP Information\n"
"OSPF interface commands\n"
"Disable OSPF capability on this interface\n"
"Disable OSPF opaque LSA capability on this interface\n"
"Address of interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct route_node *rn;
bool old_opaque_capable;

struct ospf_if_params *params;
params = IF_DEF_PARAMS(ifp);

if (ip_addr.s_addr != INADDR_ANY) {
params = ospf_get_if_params(ifp, ip_addr);
ospf_if_update_params(ifp, ip_addr);
}

old_opaque_capable = params->opaque_capable;
params->opaque_capable = (no) ? false : true;
if (params->opaque_capable != OSPF_OPAQUE_CAPABLE_DEFAULT)
SET_IF_PARAM(params, opaque_capable);
else {
UNSET_IF_PARAM(params, opaque_capable);
if (params != IF_DEF_PARAMS(ifp)) {
ospf_free_if_params(ifp, ip_addr);
ospf_if_update_params(ifp, ip_addr);
}
}

/*
* If there is a change to the opaque capability, flap the interface
* to reset all the neighbor adjacencies.
*/
if (params->opaque_capable != old_opaque_capable) {
for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
struct ospf_interface *oi = rn->info;

if (oi && (oi->state > ISM_Down) &&
(ip_addr.s_addr == INADDR_ANY ||
IPV4_ADDR_SAME(&oi->address->u.prefix4,
&ip_addr))) {
OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceDown);
OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceUp);
}
}
}
return CMD_SUCCESS;
}


DEFUN (ospf_max_metric_router_lsa_admin,
ospf_max_metric_router_lsa_admin_cmd,
Expand Down Expand Up @@ -12163,6 +12222,21 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
if (params && params->ldp_sync_info)
ospf_ldp_sync_if_write_config(vty, params);

/* Capability opaque print. */
if (OSPF_IF_PARAM_CONFIGURED(params, opaque_capable) &&
params->opaque_capable !=
OSPF_OPAQUE_CAPABLE_DEFAULT) {
if (params->opaque_capable == false)
vty_out(vty,
" no ip ospf capability opaque");
else
vty_out(vty,
" ip ospf capability opaque");
if (params != IF_DEF_PARAMS(ifp) && rn)
vty_out(vty, " %pI4", &rn->p.u.prefix4);
vty_out(vty, "\n");
}

while (1) {
if (rn == NULL)
rn = route_top(IF_OIFS_PARAMS(ifp));
Expand Down Expand Up @@ -12972,6 +13046,9 @@ static void ospf_vty_if_init(void)
install_element(INTERFACE_NODE, &ip_ospf_passive_cmd);
install_element(INTERFACE_NODE, &no_ip_ospf_passive_cmd);

/* "ip ospf capability opaque" commands. */
install_element(INTERFACE_NODE, &ip_ospf_capability_opaque_addr_cmd);

/* These commands are compatibitliy for previous version. */
install_element(INTERFACE_NODE, &ospf_authentication_key_cmd);
install_element(INTERFACE_NODE, &ospf_message_digest_key_cmd);
Expand Down
Loading

0 comments on commit 219386d

Please sign in to comment.