2023-02-08 13:17:09 +01:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2003-12-23 09:09:43 +01:00
|
|
|
/*
|
|
|
|
* IS-IS Rout(e)ing protocol - isis_zebra.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2001,2002 Sampo Saaristo
|
|
|
|
* Tampere University of Technology
|
|
|
|
* Institute of Communications Engineering
|
2015-11-12 14:24:22 +01:00
|
|
|
* Copyright (C) 2013-2015 Christian Franke <chris@opensourcerouting.org>
|
2003-12-23 09:09:43 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <zebra.h>
|
|
|
|
|
2023-03-07 20:22:48 +01:00
|
|
|
#include "frrevent.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "command.h"
|
|
|
|
#include "memory.h"
|
|
|
|
#include "log.h"
|
2019-08-06 22:43:46 +02:00
|
|
|
#include "lib_errors.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "if.h"
|
|
|
|
#include "network.h"
|
|
|
|
#include "prefix.h"
|
|
|
|
#include "zclient.h"
|
|
|
|
#include "stream.h"
|
|
|
|
#include "linklist.h"
|
2015-11-12 14:24:22 +01:00
|
|
|
#include "nexthop.h"
|
*: add VRF ID in the API message header
The API messages are used by zebra to exchange the interfaces, addresses,
routes and router-id information with its clients. To distinguish which
VRF the information belongs to, a new field "VRF ID" is added in the
message header. And hence the message version is increased to 3.
* The new field "VRF ID" in the message header:
Length (2 bytes)
Marker (1 byte)
Version (1 byte)
VRF ID (2 bytes, newly added)
Command (2 bytes)
- Client side:
- zclient_create_header() adds the VRF ID in the message header.
- zclient_read() extracts and validates the VRF ID from the header,
and passes the VRF ID to the callback functions registered to
the API messages.
- All relative functions are appended with a new parameter "vrf_id",
including all the callback functions.
- "vrf_id" is also added to "struct zapi_ipv4" and "struct zapi_ipv6".
Clients need to correctly set the VRF ID when using the API
functions zapi_ipv4_route() and zapi_ipv6_route().
- Till now all messages sent from a client have the default VRF ID
"0" in the header.
- The HELLO message is special, which is used as the heart-beat of
a client, and has no relation with VRF. The VRF ID in the HELLO
message header will always be 0 and ignored by zebra.
- Zebra side:
- zserv_create_header() adds the VRF ID in the message header.
- zebra_client_read() extracts and validates the VRF ID from the
header, and passes the VRF ID to the functions which process
the received messages.
- All relative functions are appended with a new parameter "vrf_id".
* Suppress the messages in a VRF which a client does not care:
Some clients may not care about the information in the VRF X, and
zebra should not send the messages in the VRF X to those clients.
Extra flags are used to indicate which VRF is registered by a client,
and a new message ZEBRA_VRF_UNREGISTER is introduced to let a client
can unregister a VRF when it does not need any information in that
VRF.
A client sends any message other than ZEBRA_VRF_UNREGISTER in a VRF
will automatically register to that VRF.
- lib/vrf:
A new utility "VRF bit-map" is provided to manage the flags for
VRFs, one bit per VRF ID.
- Use vrf_bitmap_init()/vrf_bitmap_free() to initialize/free a
bit-map;
- Use vrf_bitmap_set()/vrf_bitmap_unset() to set/unset a flag
in the given bit-map, corresponding to the given VRF ID;
- Use vrf_bitmap_check() to test whether the flag, in the given
bit-map and for the given VRF ID, is set.
- Client side:
- In "struct zclient", the following flags are changed from
"u_char" to "vrf_bitmap_t":
redist[ZEBRA_ROUTE_MAX]
default_information
These flags are extended for each VRF, and controlled by the
clients themselves (or with the help of zclient_redistribute()
and zclient_redistribute_default()).
- Zebra side:
- In "struct zserv", the following flags are changed from
"u_char" to "vrf_bitmap_t":
redist[ZEBRA_ROUTE_MAX]
redist_default
ifinfo
ridinfo
These flags are extended for each VRF, as the VRF registration
flags. They are maintained on receiving a ZEBRA_XXX_ADD or
ZEBRA_XXX_DELETE message.
When sending an interface/address/route/router-id message in
a VRF to a client, if the corresponding VRF registration flag
is not set, this message will not be dropped by zebra.
- A new function zread_vrf_unregister() is introduced to process
the new command ZEBRA_VRF_UNREGISTER. All the VRF registration
flags are cleared for the requested VRF.
Those clients, who support only the default VRF, will never receive
a message in a non-default VRF, thanks to the filter in zebra.
* New callback for the event of successful connection to zebra:
- zclient_start() is splitted, keeping only the code of connecting
to zebra.
- Now zclient_init()=>zclient_connect()=>zclient_start() operations
are purely dealing with the connection to zbera.
- Once zebra is successfully connected, at the end of zclient_start(),
a new callback is used to inform the client about connection.
- Till now, in the callback of connect-to-zebra event, all clients
send messages to zebra to request the router-id/interface/routes
information in the default VRF.
Of corse in future the client can do anything it wants in this
callback. For example, it may send requests for both default VRF
and some non-default VRFs.
Signed-off-by: Feng Lu <lu.feng@6wind.com>
Reviewed-by: Alain Ritoux <alain.ritoux@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
Conflicts:
lib/zclient.h
lib/zebra.h
zebra/zserv.c
zebra/zserv.h
Conflicts:
bgpd/bgp_nexthop.c
bgpd/bgp_nht.c
bgpd/bgp_zebra.c
isisd/isis_zebra.c
lib/zclient.c
lib/zclient.h
lib/zebra.h
nhrpd/nhrp_interface.c
nhrpd/nhrp_route.c
nhrpd/nhrpd.h
ospf6d/ospf6_zebra.c
ospf6d/ospf6_zebra.h
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
pimd/pim_zebra.c
pimd/pim_zlookup.c
ripd/rip_zebra.c
ripngd/ripng_zebra.c
zebra/redistribute.c
zebra/rt_netlink.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zserv.c
zebra/zserv.h
2014-10-16 03:52:36 +02:00
|
|
|
#include "vrf.h"
|
2017-09-12 04:05:16 +02:00
|
|
|
#include "libfrr.h"
|
2021-05-06 13:44:05 +02:00
|
|
|
#include "bfd.h"
|
2021-06-22 19:59:02 +02:00
|
|
|
#include "link_state.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
|
|
|
|
#include "isisd/isis_constants.h"
|
|
|
|
#include "isisd/isis_common.h"
|
2012-03-24 16:35:20 +01:00
|
|
|
#include "isisd/isis_flags.h"
|
|
|
|
#include "isisd/isis_misc.h"
|
|
|
|
#include "isisd/isis_circuit.h"
|
2005-09-04 23:36:36 +02:00
|
|
|
#include "isisd/isisd.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "isisd/isis_circuit.h"
|
|
|
|
#include "isisd/isis_csm.h"
|
2012-03-24 16:35:20 +01:00
|
|
|
#include "isisd/isis_lsp.h"
|
2020-11-26 03:39:09 +01:00
|
|
|
#include "isisd/isis_spf.h"
|
|
|
|
#include "isisd/isis_spf_private.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
#include "isisd/isis_route.h"
|
|
|
|
#include "isisd/isis_zebra.h"
|
2020-05-04 18:26:21 +02:00
|
|
|
#include "isisd/isis_adjacency.h"
|
2016-04-19 19:03:05 +02:00
|
|
|
#include "isisd/isis_te.h"
|
2019-08-04 03:02:37 +02:00
|
|
|
#include "isisd/isis_sr.h"
|
2020-07-22 20:32:35 +02:00
|
|
|
#include "isisd/isis_ldp_sync.h"
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
struct zclient *isis_zclient;
|
2019-08-04 03:02:37 +02:00
|
|
|
static struct zclient *zclient_sync;
|
|
|
|
|
2004-10-03 20:18:34 +02:00
|
|
|
/* Router-id update message from zebra. */
|
2019-05-03 21:42:59 +02:00
|
|
|
static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
|
2004-10-03 20:18:34 +02:00
|
|
|
{
|
2012-03-24 16:35:20 +01:00
|
|
|
struct isis_area *area;
|
|
|
|
struct listnode *node;
|
2004-10-03 20:18:34 +02:00
|
|
|
struct prefix router_id;
|
2020-07-13 14:37:59 +02:00
|
|
|
struct isis *isis = NULL;
|
|
|
|
|
|
|
|
isis = isis_lookup_by_vrfid(vrf_id);
|
|
|
|
|
|
|
|
if (isis == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
zebra_router_id_update_read(zclient->ibuf, &router_id);
|
|
|
|
if (isis->router_id == router_id.u.prefix4.s_addr)
|
|
|
|
return 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2012-03-24 16:35:20 +01:00
|
|
|
isis->router_id = router_id.u.prefix4.s_addr;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
|
|
|
|
if (listcount(area->area_addrs) > 0)
|
|
|
|
lsp_regenerate_schedule(area, area->is_type, 0);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2004-10-03 20:18:34 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2019-05-03 21:42:59 +02:00
|
|
|
static int isis_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2020-10-08 19:05:08 +02:00
|
|
|
struct isis_circuit *circuit;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct connected *c;
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD,
|
*: add VRF ID in the API message header
The API messages are used by zebra to exchange the interfaces, addresses,
routes and router-id information with its clients. To distinguish which
VRF the information belongs to, a new field "VRF ID" is added in the
message header. And hence the message version is increased to 3.
* The new field "VRF ID" in the message header:
Length (2 bytes)
Marker (1 byte)
Version (1 byte)
VRF ID (2 bytes, newly added)
Command (2 bytes)
- Client side:
- zclient_create_header() adds the VRF ID in the message header.
- zclient_read() extracts and validates the VRF ID from the header,
and passes the VRF ID to the callback functions registered to
the API messages.
- All relative functions are appended with a new parameter "vrf_id",
including all the callback functions.
- "vrf_id" is also added to "struct zapi_ipv4" and "struct zapi_ipv6".
Clients need to correctly set the VRF ID when using the API
functions zapi_ipv4_route() and zapi_ipv6_route().
- Till now all messages sent from a client have the default VRF ID
"0" in the header.
- The HELLO message is special, which is used as the heart-beat of
a client, and has no relation with VRF. The VRF ID in the HELLO
message header will always be 0 and ignored by zebra.
- Zebra side:
- zserv_create_header() adds the VRF ID in the message header.
- zebra_client_read() extracts and validates the VRF ID from the
header, and passes the VRF ID to the functions which process
the received messages.
- All relative functions are appended with a new parameter "vrf_id".
* Suppress the messages in a VRF which a client does not care:
Some clients may not care about the information in the VRF X, and
zebra should not send the messages in the VRF X to those clients.
Extra flags are used to indicate which VRF is registered by a client,
and a new message ZEBRA_VRF_UNREGISTER is introduced to let a client
can unregister a VRF when it does not need any information in that
VRF.
A client sends any message other than ZEBRA_VRF_UNREGISTER in a VRF
will automatically register to that VRF.
- lib/vrf:
A new utility "VRF bit-map" is provided to manage the flags for
VRFs, one bit per VRF ID.
- Use vrf_bitmap_init()/vrf_bitmap_free() to initialize/free a
bit-map;
- Use vrf_bitmap_set()/vrf_bitmap_unset() to set/unset a flag
in the given bit-map, corresponding to the given VRF ID;
- Use vrf_bitmap_check() to test whether the flag, in the given
bit-map and for the given VRF ID, is set.
- Client side:
- In "struct zclient", the following flags are changed from
"u_char" to "vrf_bitmap_t":
redist[ZEBRA_ROUTE_MAX]
default_information
These flags are extended for each VRF, and controlled by the
clients themselves (or with the help of zclient_redistribute()
and zclient_redistribute_default()).
- Zebra side:
- In "struct zserv", the following flags are changed from
"u_char" to "vrf_bitmap_t":
redist[ZEBRA_ROUTE_MAX]
redist_default
ifinfo
ridinfo
These flags are extended for each VRF, as the VRF registration
flags. They are maintained on receiving a ZEBRA_XXX_ADD or
ZEBRA_XXX_DELETE message.
When sending an interface/address/route/router-id message in
a VRF to a client, if the corresponding VRF registration flag
is not set, this message will not be dropped by zebra.
- A new function zread_vrf_unregister() is introduced to process
the new command ZEBRA_VRF_UNREGISTER. All the VRF registration
flags are cleared for the requested VRF.
Those clients, who support only the default VRF, will never receive
a message in a non-default VRF, thanks to the filter in zebra.
* New callback for the event of successful connection to zebra:
- zclient_start() is splitted, keeping only the code of connecting
to zebra.
- Now zclient_init()=>zclient_connect()=>zclient_start() operations
are purely dealing with the connection to zbera.
- Once zebra is successfully connected, at the end of zclient_start(),
a new callback is used to inform the client about connection.
- Till now, in the callback of connect-to-zebra event, all clients
send messages to zebra to request the router-id/interface/routes
information in the default VRF.
Of corse in future the client can do anything it wants in this
callback. For example, it may send requests for both default VRF
and some non-default VRFs.
Signed-off-by: Feng Lu <lu.feng@6wind.com>
Reviewed-by: Alain Ritoux <alain.ritoux@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
Conflicts:
lib/zclient.h
lib/zebra.h
zebra/zserv.c
zebra/zserv.h
Conflicts:
bgpd/bgp_nexthop.c
bgpd/bgp_nht.c
bgpd/bgp_zebra.c
isisd/isis_zebra.c
lib/zclient.c
lib/zclient.h
lib/zebra.h
nhrpd/nhrp_interface.c
nhrpd/nhrp_route.c
nhrpd/nhrpd.h
ospf6d/ospf6_zebra.c
ospf6d/ospf6_zebra.h
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
pimd/pim_zebra.c
pimd/pim_zlookup.c
ripd/rip_zebra.c
ripngd/ripng_zebra.c
zebra/redistribute.c
zebra/rt_netlink.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zserv.c
zebra/zserv.h
2014-10-16 03:52:36 +02:00
|
|
|
zclient->ibuf, vrf_id);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (c == NULL)
|
|
|
|
return 0;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2020-10-08 19:06:27 +02:00
|
|
|
#ifdef EXTREME_DEBUG
|
2020-10-24 15:55:27 +02:00
|
|
|
if (c->address->family == AF_INET)
|
2020-10-18 13:33:54 +02:00
|
|
|
zlog_debug("connected IP address %pFX", c->address);
|
2020-10-24 15:55:27 +02:00
|
|
|
if (c->address->family == AF_INET6)
|
2020-10-18 13:33:54 +02:00
|
|
|
zlog_debug("connected IPv6 address %pFX", c->address);
|
2003-12-23 09:09:43 +01:00
|
|
|
#endif /* EXTREME_DEBUG */
|
2020-10-08 19:05:08 +02:00
|
|
|
|
|
|
|
if (if_is_operative(c->ifp)) {
|
|
|
|
circuit = circuit_scan_by_ifp(c->ifp);
|
|
|
|
if (circuit)
|
|
|
|
isis_circuit_add_addr(circuit, c);
|
|
|
|
}
|
2003-12-23 09:09:43 +01:00
|
|
|
|
2023-07-28 01:35:10 +02:00
|
|
|
sr_if_addr_update(c->ifp);
|
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-03 21:42:59 +02:00
|
|
|
static int isis_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2020-10-08 19:05:08 +02:00
|
|
|
struct isis_circuit *circuit;
|
2003-12-23 09:09:43 +01:00
|
|
|
struct connected *c;
|
|
|
|
|
2004-09-10 22:48:21 +02:00
|
|
|
c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE,
|
*: add VRF ID in the API message header
The API messages are used by zebra to exchange the interfaces, addresses,
routes and router-id information with its clients. To distinguish which
VRF the information belongs to, a new field "VRF ID" is added in the
message header. And hence the message version is increased to 3.
* The new field "VRF ID" in the message header:
Length (2 bytes)
Marker (1 byte)
Version (1 byte)
VRF ID (2 bytes, newly added)
Command (2 bytes)
- Client side:
- zclient_create_header() adds the VRF ID in the message header.
- zclient_read() extracts and validates the VRF ID from the header,
and passes the VRF ID to the callback functions registered to
the API messages.
- All relative functions are appended with a new parameter "vrf_id",
including all the callback functions.
- "vrf_id" is also added to "struct zapi_ipv4" and "struct zapi_ipv6".
Clients need to correctly set the VRF ID when using the API
functions zapi_ipv4_route() and zapi_ipv6_route().
- Till now all messages sent from a client have the default VRF ID
"0" in the header.
- The HELLO message is special, which is used as the heart-beat of
a client, and has no relation with VRF. The VRF ID in the HELLO
message header will always be 0 and ignored by zebra.
- Zebra side:
- zserv_create_header() adds the VRF ID in the message header.
- zebra_client_read() extracts and validates the VRF ID from the
header, and passes the VRF ID to the functions which process
the received messages.
- All relative functions are appended with a new parameter "vrf_id".
* Suppress the messages in a VRF which a client does not care:
Some clients may not care about the information in the VRF X, and
zebra should not send the messages in the VRF X to those clients.
Extra flags are used to indicate which VRF is registered by a client,
and a new message ZEBRA_VRF_UNREGISTER is introduced to let a client
can unregister a VRF when it does not need any information in that
VRF.
A client sends any message other than ZEBRA_VRF_UNREGISTER in a VRF
will automatically register to that VRF.
- lib/vrf:
A new utility "VRF bit-map" is provided to manage the flags for
VRFs, one bit per VRF ID.
- Use vrf_bitmap_init()/vrf_bitmap_free() to initialize/free a
bit-map;
- Use vrf_bitmap_set()/vrf_bitmap_unset() to set/unset a flag
in the given bit-map, corresponding to the given VRF ID;
- Use vrf_bitmap_check() to test whether the flag, in the given
bit-map and for the given VRF ID, is set.
- Client side:
- In "struct zclient", the following flags are changed from
"u_char" to "vrf_bitmap_t":
redist[ZEBRA_ROUTE_MAX]
default_information
These flags are extended for each VRF, and controlled by the
clients themselves (or with the help of zclient_redistribute()
and zclient_redistribute_default()).
- Zebra side:
- In "struct zserv", the following flags are changed from
"u_char" to "vrf_bitmap_t":
redist[ZEBRA_ROUTE_MAX]
redist_default
ifinfo
ridinfo
These flags are extended for each VRF, as the VRF registration
flags. They are maintained on receiving a ZEBRA_XXX_ADD or
ZEBRA_XXX_DELETE message.
When sending an interface/address/route/router-id message in
a VRF to a client, if the corresponding VRF registration flag
is not set, this message will not be dropped by zebra.
- A new function zread_vrf_unregister() is introduced to process
the new command ZEBRA_VRF_UNREGISTER. All the VRF registration
flags are cleared for the requested VRF.
Those clients, who support only the default VRF, will never receive
a message in a non-default VRF, thanks to the filter in zebra.
* New callback for the event of successful connection to zebra:
- zclient_start() is splitted, keeping only the code of connecting
to zebra.
- Now zclient_init()=>zclient_connect()=>zclient_start() operations
are purely dealing with the connection to zbera.
- Once zebra is successfully connected, at the end of zclient_start(),
a new callback is used to inform the client about connection.
- Till now, in the callback of connect-to-zebra event, all clients
send messages to zebra to request the router-id/interface/routes
information in the default VRF.
Of corse in future the client can do anything it wants in this
callback. For example, it may send requests for both default VRF
and some non-default VRFs.
Signed-off-by: Feng Lu <lu.feng@6wind.com>
Reviewed-by: Alain Ritoux <alain.ritoux@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
Conflicts:
lib/zclient.h
lib/zebra.h
zebra/zserv.c
zebra/zserv.h
Conflicts:
bgpd/bgp_nexthop.c
bgpd/bgp_nht.c
bgpd/bgp_zebra.c
isisd/isis_zebra.c
lib/zclient.c
lib/zclient.h
lib/zebra.h
nhrpd/nhrp_interface.c
nhrpd/nhrp_route.c
nhrpd/nhrpd.h
ospf6d/ospf6_zebra.c
ospf6d/ospf6_zebra.h
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
pimd/pim_zebra.c
pimd/pim_zlookup.c
ripd/rip_zebra.c
ripngd/ripng_zebra.c
zebra/redistribute.c
zebra/rt_netlink.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zserv.c
zebra/zserv.h
2014-10-16 03:52:36 +02:00
|
|
|
zclient->ibuf, vrf_id);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
if (c == NULL)
|
|
|
|
return 0;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2004-09-14 15:54:30 +02:00
|
|
|
#ifdef EXTREME_DEBUG
|
2020-10-24 15:55:27 +02:00
|
|
|
if (c->address->family == AF_INET)
|
2020-10-18 13:33:54 +02:00
|
|
|
zlog_debug("disconnected IP address %pFX", c->address);
|
2020-10-24 15:55:27 +02:00
|
|
|
if (c->address->family == AF_INET6)
|
2020-10-18 13:33:54 +02:00
|
|
|
zlog_debug("disconnected IPv6 address %pFX", c->address);
|
2004-09-14 15:54:30 +02:00
|
|
|
#endif /* EXTREME_DEBUG */
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2020-10-08 19:05:08 +02:00
|
|
|
if (if_is_operative(c->ifp)) {
|
|
|
|
circuit = circuit_scan_by_ifp(c->ifp);
|
|
|
|
if (circuit)
|
|
|
|
isis_circuit_del_addr(circuit, c);
|
|
|
|
}
|
|
|
|
|
2023-07-28 01:35:10 +02:00
|
|
|
sr_if_addr_update(c->ifp);
|
|
|
|
|
2019-10-30 01:16:28 +01:00
|
|
|
connected_free(&c);
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-03 21:42:59 +02:00
|
|
|
static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS)
|
2016-04-19 19:03:05 +02:00
|
|
|
{
|
|
|
|
struct interface *ifp;
|
2021-06-17 15:26:36 +02:00
|
|
|
bool changed = false;
|
2016-04-19 19:03:05 +02:00
|
|
|
|
2021-06-17 15:26:36 +02:00
|
|
|
ifp = zebra_interface_link_params_read(zclient->ibuf, vrf_id, &changed);
|
2016-04-19 19:03:05 +02:00
|
|
|
|
2021-06-17 15:26:36 +02:00
|
|
|
if (ifp == NULL || !changed)
|
2016-04-19 19:03:05 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Update TE TLV */
|
|
|
|
isis_mpls_te_update(ifp);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
enum isis_zebra_nexthop_type {
|
2020-09-20 07:39:28 +02:00
|
|
|
ISIS_NEXTHOP_MAIN = 0,
|
|
|
|
ISIS_NEXTHOP_BACKUP,
|
2020-08-21 00:55:42 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static int isis_zebra_add_nexthops(struct isis *isis, struct list *nexthops,
|
|
|
|
struct zapi_nexthop zapi_nexthops[],
|
|
|
|
enum isis_zebra_nexthop_type type,
|
2020-09-20 07:39:28 +02:00
|
|
|
bool mpls_lsp, uint8_t backup_nhs)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
|
|
|
struct isis_nexthop *nexthop;
|
|
|
|
struct listnode *node;
|
2017-08-21 02:18:36 +02:00
|
|
|
int count = 0;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-21 02:29:35 +02:00
|
|
|
/* Nexthops */
|
2020-08-21 00:55:42 +02:00
|
|
|
for (ALL_LIST_ELEMENTS_RO(nexthops, node, nexthop)) {
|
|
|
|
struct zapi_nexthop *api_nh;
|
|
|
|
|
2019-08-06 22:43:46 +02:00
|
|
|
if (count >= MULTIPATH_NUM)
|
|
|
|
break;
|
2020-08-21 00:55:42 +02:00
|
|
|
api_nh = &zapi_nexthops[count];
|
2019-08-06 22:43:46 +02:00
|
|
|
if (fabricd)
|
2019-11-13 22:06:06 +01:00
|
|
|
SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK);
|
2020-06-19 20:46:12 +02:00
|
|
|
api_nh->vrf_id = isis->vrf_id;
|
2019-08-06 22:43:46 +02:00
|
|
|
|
|
|
|
switch (nexthop->family) {
|
|
|
|
case AF_INET:
|
2017-08-21 02:29:35 +02:00
|
|
|
/* FIXME: can it be ? */
|
2019-08-06 22:43:46 +02:00
|
|
|
if (nexthop->ip.ipv4.s_addr != INADDR_ANY) {
|
2017-08-21 02:29:35 +02:00
|
|
|
api_nh->type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
2019-08-06 22:43:46 +02:00
|
|
|
api_nh->gate.ipv4 = nexthop->ip.ipv4;
|
2017-08-21 02:29:35 +02:00
|
|
|
} else {
|
|
|
|
api_nh->type = NEXTHOP_TYPE_IFINDEX;
|
|
|
|
}
|
2019-08-06 22:43:46 +02:00
|
|
|
break;
|
|
|
|
case AF_INET6:
|
|
|
|
if (!IN6_IS_ADDR_LINKLOCAL(&nexthop->ip.ipv6)
|
|
|
|
&& !IN6_IS_ADDR_UNSPECIFIED(&nexthop->ip.ipv6)) {
|
2017-08-21 02:29:35 +02:00
|
|
|
continue;
|
|
|
|
}
|
2019-08-06 22:43:46 +02:00
|
|
|
api_nh->gate.ipv6 = nexthop->ip.ipv6;
|
2017-08-21 02:29:35 +02:00
|
|
|
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
2019-08-06 22:43:46 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
flog_err(EC_LIB_DEVELOPMENT,
|
|
|
|
"%s: unknown address family [%d]", __func__,
|
|
|
|
nexthop->family);
|
|
|
|
exit(1);
|
2017-07-17 14:03:14 +02:00
|
|
|
}
|
2019-08-06 22:43:46 +02:00
|
|
|
|
|
|
|
api_nh->ifindex = nexthop->ifindex;
|
2020-08-21 00:55:42 +02:00
|
|
|
|
|
|
|
/* Add MPLS label(s). */
|
2020-11-20 04:54:41 +01:00
|
|
|
if (nexthop->label_stack) {
|
|
|
|
api_nh->label_num = nexthop->label_stack->num_labels;
|
|
|
|
memcpy(api_nh->labels, nexthop->label_stack->label,
|
|
|
|
sizeof(mpls_label_t) * api_nh->label_num);
|
|
|
|
} else if (nexthop->sr.present) {
|
|
|
|
api_nh->label_num = 1;
|
|
|
|
api_nh->labels[0] = nexthop->sr.label;
|
|
|
|
} else if (mpls_lsp) {
|
|
|
|
switch (type) {
|
|
|
|
case ISIS_NEXTHOP_MAIN:
|
2020-09-20 07:39:28 +02:00
|
|
|
/*
|
|
|
|
* Do not use non-SR enabled nexthops to prevent
|
|
|
|
* broken LSPs from being formed.
|
|
|
|
*/
|
|
|
|
continue;
|
2020-11-20 04:54:41 +01:00
|
|
|
case ISIS_NEXTHOP_BACKUP:
|
2020-09-20 07:39:28 +02:00
|
|
|
/*
|
|
|
|
* This is necessary because zebra requires
|
|
|
|
* the nexthops of MPLS LSPs to be labeled.
|
|
|
|
*/
|
2020-08-21 00:55:42 +02:00
|
|
|
api_nh->label_num = 1;
|
|
|
|
api_nh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
|
2020-11-20 04:54:41 +01:00
|
|
|
break;
|
2020-08-21 00:55:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Backup nexthop handling. */
|
|
|
|
if (backup_nhs) {
|
|
|
|
SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
|
|
|
|
/*
|
|
|
|
* If the backup has multiple nexthops, all of them
|
|
|
|
* protect the same primary nexthop since ECMP routes
|
|
|
|
* have no backups.
|
|
|
|
*/
|
|
|
|
api_nh->backup_num = backup_nhs;
|
|
|
|
for (int i = 0; i < backup_nhs; i++)
|
|
|
|
api_nh->backup_idx[i] = i;
|
|
|
|
}
|
2019-08-06 22:43:46 +02:00
|
|
|
count++;
|
2004-09-10 22:48:21 +02:00
|
|
|
}
|
2020-08-21 00:55:42 +02:00
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void isis_zebra_route_add_route(struct isis *isis, struct prefix *prefix,
|
|
|
|
struct prefix_ipv6 *src_p,
|
|
|
|
struct isis_route_info *route_info)
|
|
|
|
{
|
|
|
|
struct zapi_route api;
|
|
|
|
int count = 0;
|
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
if (isis_zclient->sock < 0)
|
2017-08-21 02:18:36 +02:00
|
|
|
return;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2020-11-05 13:40:26 +01:00
|
|
|
/* Uninstall the route if it doesn't have any valid nexthop. */
|
|
|
|
if (list_isempty(route_info->nexthops)) {
|
|
|
|
isis_zebra_route_del_route(isis, prefix, src_p, route_info);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-08-21 00:55:42 +02:00
|
|
|
memset(&api, 0, sizeof(api));
|
|
|
|
api.vrf_id = isis->vrf_id;
|
|
|
|
api.type = PROTO_TYPE;
|
|
|
|
api.safi = SAFI_UNICAST;
|
|
|
|
api.prefix = *prefix;
|
|
|
|
if (src_p && src_p->prefixlen) {
|
|
|
|
api.src_prefix = *src_p;
|
|
|
|
SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
|
|
|
|
}
|
|
|
|
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
|
|
|
|
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
|
|
|
|
api.metric = route_info->cost;
|
|
|
|
|
|
|
|
/* Add backup nexthops first. */
|
|
|
|
if (route_info->backup) {
|
|
|
|
count = isis_zebra_add_nexthops(
|
|
|
|
isis, route_info->backup->nexthops, api.backup_nexthops,
|
2020-09-20 07:39:28 +02:00
|
|
|
ISIS_NEXTHOP_BACKUP, false, 0);
|
2020-08-21 00:55:42 +02:00
|
|
|
if (count > 0) {
|
|
|
|
SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS);
|
|
|
|
api.backup_nexthop_num = count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add primary nexthops. */
|
|
|
|
count = isis_zebra_add_nexthops(isis, route_info->nexthops,
|
2020-09-20 07:39:28 +02:00
|
|
|
api.nexthops, ISIS_NEXTHOP_MAIN, false,
|
2020-08-21 00:55:42 +02:00
|
|
|
count);
|
|
|
|
if (!count)
|
|
|
|
return;
|
2017-08-21 02:18:36 +02:00
|
|
|
api.nexthop_num = count;
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
zclient_route_send(ZEBRA_ROUTE_ADD, isis_zclient, &api);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2020-06-19 20:46:12 +02:00
|
|
|
void isis_zebra_route_del_route(struct isis *isis,
|
|
|
|
struct prefix *prefix,
|
2019-08-08 00:42:18 +02:00
|
|
|
struct prefix_ipv6 *src_p,
|
|
|
|
struct isis_route_info *route_info)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2017-08-21 02:18:36 +02:00
|
|
|
struct zapi_route api;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
if (isis_zclient->sock < 0)
|
2003-12-23 09:09:43 +01:00
|
|
|
return;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2023-06-10 09:30:17 +02:00
|
|
|
if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
|
|
|
|
return;
|
|
|
|
|
2017-08-21 02:18:36 +02:00
|
|
|
memset(&api, 0, sizeof(api));
|
2020-06-19 20:46:12 +02:00
|
|
|
api.vrf_id = isis->vrf_id;
|
2018-03-22 15:01:08 +01:00
|
|
|
api.type = PROTO_TYPE;
|
2012-04-12 08:56:03 +02:00
|
|
|
api.safi = SAFI_UNICAST;
|
2017-08-21 02:18:36 +02:00
|
|
|
api.prefix = *prefix;
|
2018-07-26 22:53:08 +02:00
|
|
|
if (src_p && src_p->prefixlen) {
|
|
|
|
api.src_prefix = *src_p;
|
|
|
|
SET_FLAG(api.message, ZAPI_MESSAGE_SRCPFX);
|
|
|
|
}
|
2004-09-10 22:48:21 +02:00
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
zclient_route_send(ZEBRA_ROUTE_DELETE, isis_zclient, &api);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2020-05-04 19:39:20 +02:00
|
|
|
/**
|
2020-09-20 07:39:28 +02:00
|
|
|
* Install Prefix-SID label entry in the forwarding plane through Zebra.
|
2020-05-04 19:39:20 +02:00
|
|
|
*
|
2020-09-20 07:39:28 +02:00
|
|
|
* @param area IS-IS area
|
|
|
|
* @param prefix Route prefix
|
|
|
|
* @param rinfo Route information
|
|
|
|
* @param psid Prefix-SID information
|
2020-05-04 19:39:20 +02:00
|
|
|
*/
|
2020-09-20 07:39:28 +02:00
|
|
|
void isis_zebra_prefix_sid_install(struct isis_area *area,
|
|
|
|
struct prefix *prefix,
|
|
|
|
struct isis_sr_psid_info *psid)
|
2019-08-04 03:02:37 +02:00
|
|
|
{
|
|
|
|
struct zapi_labels zl;
|
2020-08-21 00:55:42 +02:00
|
|
|
int count = 0;
|
2019-08-04 03:02:37 +02:00
|
|
|
|
2021-12-11 04:01:07 +01:00
|
|
|
sr_debug("ISIS-Sr (%s): update label %u for prefix %pFX algorithm %u",
|
|
|
|
area->area_tag, psid->label, prefix, psid->algorithm);
|
2020-09-20 07:39:28 +02:00
|
|
|
|
2019-08-04 03:02:37 +02:00
|
|
|
/* Prepare message. */
|
|
|
|
memset(&zl, 0, sizeof(zl));
|
|
|
|
zl.type = ZEBRA_LSP_ISIS_SR;
|
2020-09-20 07:39:28 +02:00
|
|
|
zl.local_label = psid->label;
|
|
|
|
|
|
|
|
/* Local routes don't have any nexthop and require special handling. */
|
2022-01-04 09:15:56 +01:00
|
|
|
if (list_isempty(psid->nexthops)) {
|
2020-09-20 07:39:28 +02:00
|
|
|
struct zapi_nexthop *znh;
|
|
|
|
struct interface *ifp;
|
2019-08-04 03:02:37 +02:00
|
|
|
|
|
|
|
ifp = if_lookup_by_name("lo", VRF_DEFAULT);
|
|
|
|
if (!ifp) {
|
|
|
|
zlog_warn(
|
|
|
|
"%s: couldn't install Prefix-SID %pFX: loopback interface not found",
|
2020-09-20 07:39:28 +02:00
|
|
|
__func__, prefix);
|
2019-08-04 03:02:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
znh = &zl.nexthops[zl.nexthop_num++];
|
|
|
|
znh->type = NEXTHOP_TYPE_IFINDEX;
|
|
|
|
znh->ifindex = ifp->ifindex;
|
2020-03-03 16:59:33 +01:00
|
|
|
znh->label_num = 1;
|
|
|
|
znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
|
2020-09-20 07:39:28 +02:00
|
|
|
} else {
|
2020-08-21 00:55:42 +02:00
|
|
|
/* Add backup nexthops first. */
|
2022-01-04 09:15:56 +01:00
|
|
|
if (psid->nexthops_backup) {
|
2020-08-21 00:55:42 +02:00
|
|
|
count = isis_zebra_add_nexthops(
|
2022-01-04 09:15:56 +01:00
|
|
|
area->isis, psid->nexthops_backup,
|
2020-09-20 07:39:28 +02:00
|
|
|
zl.backup_nexthops, ISIS_NEXTHOP_BACKUP, true,
|
2020-08-21 00:55:42 +02:00
|
|
|
0);
|
|
|
|
if (count > 0) {
|
|
|
|
SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
|
|
|
|
zl.backup_nexthop_num = count;
|
|
|
|
}
|
2019-08-04 03:02:37 +02:00
|
|
|
}
|
2020-08-21 00:55:42 +02:00
|
|
|
|
|
|
|
/* Add primary nexthops. */
|
2022-01-04 09:15:56 +01:00
|
|
|
count = isis_zebra_add_nexthops(area->isis, psid->nexthops,
|
2020-09-20 07:39:28 +02:00
|
|
|
zl.nexthops, ISIS_NEXTHOP_MAIN,
|
|
|
|
true, count);
|
2020-08-21 00:55:42 +02:00
|
|
|
if (!count)
|
|
|
|
return;
|
|
|
|
zl.nexthop_num = count;
|
2019-08-04 03:02:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Send message to zebra. */
|
2025-01-23 19:16:11 +01:00
|
|
|
(void)zebra_send_mpls_labels(isis_zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl);
|
2019-08-04 03:02:37 +02:00
|
|
|
}
|
|
|
|
|
2020-05-04 19:39:20 +02:00
|
|
|
/**
|
2020-09-20 07:39:28 +02:00
|
|
|
* Uninstall Prefix-SID label entry from the forwarding plane through Zebra.
|
2020-05-04 19:39:20 +02:00
|
|
|
*
|
2020-09-20 07:39:28 +02:00
|
|
|
* @param area IS-IS area
|
|
|
|
* @param prefix Route prefix
|
|
|
|
* @param rinfo Route information
|
|
|
|
* @param psid Prefix-SID information
|
2020-05-04 19:39:20 +02:00
|
|
|
*/
|
2020-09-20 07:39:28 +02:00
|
|
|
void isis_zebra_prefix_sid_uninstall(struct isis_area *area,
|
|
|
|
struct prefix *prefix,
|
|
|
|
struct isis_route_info *rinfo,
|
|
|
|
struct isis_sr_psid_info *psid)
|
2019-08-04 03:02:37 +02:00
|
|
|
{
|
|
|
|
struct zapi_labels zl;
|
|
|
|
|
2021-12-11 04:01:07 +01:00
|
|
|
sr_debug("ISIS-Sr (%s): delete label %u for prefix %pFX algorithm %u",
|
|
|
|
area->area_tag, psid->label, prefix, psid->algorithm);
|
2020-09-20 07:39:28 +02:00
|
|
|
|
2019-08-04 03:02:37 +02:00
|
|
|
/* Prepare message. */
|
|
|
|
memset(&zl, 0, sizeof(zl));
|
|
|
|
zl.type = ZEBRA_LSP_ISIS_SR;
|
2020-09-20 07:39:28 +02:00
|
|
|
zl.local_label = psid->label;
|
2019-08-04 03:02:37 +02:00
|
|
|
|
|
|
|
/* Send message to zebra. */
|
2025-01-23 19:16:11 +01:00
|
|
|
(void)zebra_send_mpls_labels(isis_zclient, ZEBRA_MPLS_LABELS_DELETE, &zl);
|
2019-08-04 03:02:37 +02:00
|
|
|
}
|
|
|
|
|
2020-05-04 19:39:20 +02:00
|
|
|
/**
|
|
|
|
* Send (LAN)-Adjacency-SID to ZEBRA for installation or deletion.
|
|
|
|
*
|
|
|
|
* @param cmd ZEBRA_MPLS_LABELS_ADD or ZEBRA_ROUTE_DELETE
|
|
|
|
* @param sra Segment Routing Adjacency-SID
|
|
|
|
*/
|
2020-05-04 18:26:21 +02:00
|
|
|
void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
|
|
|
|
{
|
2020-08-31 20:24:02 +02:00
|
|
|
struct isis *isis = sra->adj->circuit->area->isis;
|
2020-05-04 18:26:21 +02:00
|
|
|
struct zapi_labels zl;
|
|
|
|
struct zapi_nexthop *znh;
|
|
|
|
|
|
|
|
if (cmd != ZEBRA_MPLS_LABELS_ADD && cmd != ZEBRA_MPLS_LABELS_DELETE) {
|
|
|
|
flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
|
|
|
|
__func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sr_debug(" |- %s label %u for interface %s",
|
|
|
|
cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete",
|
2020-08-31 20:24:02 +02:00
|
|
|
sra->input_label, sra->adj->circuit->interface->name);
|
2020-05-04 18:26:21 +02:00
|
|
|
|
|
|
|
memset(&zl, 0, sizeof(zl));
|
|
|
|
zl.type = ZEBRA_LSP_ISIS_SR;
|
2020-08-31 20:24:02 +02:00
|
|
|
zl.local_label = sra->input_label;
|
2020-05-04 18:26:21 +02:00
|
|
|
zl.nexthop_num = 1;
|
|
|
|
znh = &zl.nexthops[0];
|
|
|
|
znh->gate = sra->nexthop.address;
|
|
|
|
znh->type = (sra->nexthop.family == AF_INET)
|
|
|
|
? NEXTHOP_TYPE_IPV4_IFINDEX
|
|
|
|
: NEXTHOP_TYPE_IPV6_IFINDEX;
|
|
|
|
znh->ifindex = sra->adj->circuit->interface->ifindex;
|
|
|
|
znh->label_num = 1;
|
|
|
|
znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
|
|
|
|
|
2020-08-31 20:24:02 +02:00
|
|
|
/* Set backup nexthops. */
|
2024-04-03 15:58:05 +02:00
|
|
|
if (sra->type == ISIS_SR_ADJ_BACKUP) {
|
2020-08-31 20:24:02 +02:00
|
|
|
int count;
|
|
|
|
|
|
|
|
count = isis_zebra_add_nexthops(isis, sra->backup_nexthops,
|
|
|
|
zl.backup_nexthops,
|
2020-09-20 07:39:28 +02:00
|
|
|
ISIS_NEXTHOP_BACKUP, true, 0);
|
2020-08-31 20:24:02 +02:00
|
|
|
if (count > 0) {
|
|
|
|
SET_FLAG(zl.message, ZAPI_LABELS_HAS_BACKUPS);
|
|
|
|
zl.backup_nexthop_num = count;
|
|
|
|
|
|
|
|
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
|
|
|
|
znh->backup_num = count;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
znh->backup_idx[i] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
(void)zebra_send_mpls_labels(isis_zclient, cmd, &zl);
|
2020-05-04 18:26:21 +02:00
|
|
|
}
|
|
|
|
|
2019-05-03 21:42:59 +02:00
|
|
|
static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2017-08-21 03:10:50 +02:00
|
|
|
struct zapi_route api;
|
2020-07-13 14:37:59 +02:00
|
|
|
struct isis *isis = NULL;
|
|
|
|
|
|
|
|
isis = isis_lookup_by_vrfid(vrf_id);
|
|
|
|
|
|
|
|
if (isis == NULL)
|
|
|
|
return -1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2017-08-21 03:10:50 +02:00
|
|
|
if (zapi_route_decode(zclient->ibuf, &api) < 0)
|
|
|
|
return -1;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-02-22 16:20:51 +01:00
|
|
|
if (api.prefix.family == AF_INET6
|
|
|
|
&& IN6_IS_ADDR_LINKLOCAL(&api.prefix.u.prefix6))
|
|
|
|
return 0;
|
|
|
|
|
2015-11-12 14:24:22 +01:00
|
|
|
/*
|
|
|
|
* Avoid advertising a false default reachability. (A default
|
|
|
|
* route installed by IS-IS gets redistributed from zebra back
|
|
|
|
* into IS-IS causing us to start advertising default reachabity
|
|
|
|
* without this check)
|
|
|
|
*/
|
2018-07-22 21:49:02 +02:00
|
|
|
if (api.prefix.prefixlen == 0
|
|
|
|
&& api.src_prefix.prefixlen == 0
|
2018-03-22 15:01:08 +01:00
|
|
|
&& api.type == PROTO_TYPE) {
|
2019-05-03 21:42:59 +02:00
|
|
|
cmd = ZEBRA_REDISTRIBUTE_ROUTE_DEL;
|
2018-07-22 21:49:02 +02:00
|
|
|
}
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-05-03 21:42:59 +02:00
|
|
|
if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
|
2020-07-13 14:37:59 +02:00
|
|
|
isis_redist_add(isis, api.type, &api.prefix, &api.src_prefix,
|
2023-07-03 18:01:52 +02:00
|
|
|
api.distance, api.metric, api.tag, api.instance);
|
2015-11-12 14:24:22 +01:00
|
|
|
else
|
2023-07-03 18:01:52 +02:00
|
|
|
isis_redist_delete(isis, api.type, &api.prefix, &api.src_prefix,
|
|
|
|
api.instance);
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2003-12-23 09:09:43 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int isis_distribute_list_update(int routetype)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-07-03 18:01:52 +02:00
|
|
|
void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id,
|
|
|
|
uint16_t tableid)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2015-11-12 14:24:22 +01:00
|
|
|
if (type == DEFAULT_ROUTE)
|
|
|
|
zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
|
2025-01-23 19:16:11 +01:00
|
|
|
isis_zclient, afi, vrf_id);
|
2015-11-12 14:24:22 +01:00
|
|
|
else
|
2025-01-23 19:16:11 +01:00
|
|
|
zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, isis_zclient, afi, type,
|
2023-07-03 18:01:52 +02:00
|
|
|
tableid, vrf_id);
|
2015-11-12 14:24:22 +01:00
|
|
|
}
|
|
|
|
|
2023-07-03 18:01:52 +02:00
|
|
|
void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id,
|
|
|
|
uint16_t tableid)
|
2015-11-12 14:24:22 +01:00
|
|
|
{
|
|
|
|
if (type == DEFAULT_ROUTE)
|
|
|
|
zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
|
2025-01-23 19:16:11 +01:00
|
|
|
isis_zclient, afi, vrf_id);
|
2015-11-12 14:24:22 +01:00
|
|
|
else
|
2025-01-23 19:16:11 +01:00
|
|
|
zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, isis_zclient, afi,
|
2023-07-03 18:01:52 +02:00
|
|
|
type, tableid, vrf_id);
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
|
|
|
|
2020-11-26 03:39:09 +01:00
|
|
|
/**
|
|
|
|
* Register RLFA with LDP.
|
|
|
|
*/
|
|
|
|
int isis_zebra_rlfa_register(struct isis_spftree *spftree, struct rlfa *rlfa)
|
|
|
|
{
|
|
|
|
struct isis_area *area = spftree->area;
|
|
|
|
struct zapi_rlfa_request zr = {};
|
|
|
|
int ret;
|
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
if (!isis_zclient)
|
2020-11-26 03:39:09 +01:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
zr.igp.vrf_id = area->isis->vrf_id;
|
|
|
|
zr.igp.protocol = ZEBRA_ROUTE_ISIS;
|
|
|
|
strlcpy(zr.igp.isis.area_tag, area->area_tag,
|
|
|
|
sizeof(zr.igp.isis.area_tag));
|
|
|
|
zr.igp.isis.spf.tree_id = spftree->tree_id;
|
|
|
|
zr.igp.isis.spf.level = spftree->level;
|
|
|
|
zr.igp.isis.spf.run_id = spftree->runcount;
|
|
|
|
zr.destination = rlfa->prefix;
|
|
|
|
zr.pq_address = rlfa->pq_address;
|
|
|
|
|
|
|
|
zlog_debug("ISIS-LFA: registering RLFA %pFX@%pI4 with LDP",
|
|
|
|
&rlfa->prefix, &rlfa->pq_address);
|
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
ret = zclient_send_opaque_unicast(isis_zclient, LDP_RLFA_REGISTER,
|
2020-11-26 03:39:09 +01:00
|
|
|
ZEBRA_ROUTE_LDP, 0, 0,
|
|
|
|
(const uint8_t *)&zr, sizeof(zr));
|
|
|
|
if (ret == ZCLIENT_SEND_FAILURE) {
|
|
|
|
zlog_warn("ISIS-LFA: failed to register RLFA with LDP");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unregister all RLFAs from the given SPF tree with LDP.
|
|
|
|
*/
|
|
|
|
void isis_zebra_rlfa_unregister_all(struct isis_spftree *spftree)
|
|
|
|
{
|
|
|
|
struct isis_area *area = spftree->area;
|
|
|
|
struct zapi_rlfa_igp igp = {};
|
|
|
|
int ret;
|
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
if (!isis_zclient || spftree->type != SPF_TYPE_FORWARD ||
|
|
|
|
CHECK_FLAG(spftree->flags, F_SPFTREE_NO_ADJACENCIES))
|
2020-11-26 03:39:09 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (IS_DEBUG_LFA)
|
|
|
|
zlog_debug("ISIS-LFA: unregistering all RLFAs with LDP");
|
|
|
|
|
|
|
|
igp.vrf_id = area->isis->vrf_id;
|
|
|
|
igp.protocol = ZEBRA_ROUTE_ISIS;
|
|
|
|
strlcpy(igp.isis.area_tag, area->area_tag, sizeof(igp.isis.area_tag));
|
|
|
|
igp.isis.spf.tree_id = spftree->tree_id;
|
|
|
|
igp.isis.spf.level = spftree->level;
|
|
|
|
igp.isis.spf.run_id = spftree->runcount;
|
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
ret = zclient_send_opaque_unicast(isis_zclient, LDP_RLFA_UNREGISTER_ALL,
|
2020-11-26 03:39:09 +01:00
|
|
|
ZEBRA_ROUTE_LDP, 0, 0,
|
|
|
|
(const uint8_t *)&igp, sizeof(igp));
|
|
|
|
if (ret == ZCLIENT_SEND_FAILURE)
|
|
|
|
zlog_warn("ISIS-LFA: failed to unregister RLFA with LDP");
|
|
|
|
}
|
|
|
|
|
2020-04-10 17:12:48 +02:00
|
|
|
/* Label Manager Functions */
|
|
|
|
|
2020-06-04 18:03:04 +02:00
|
|
|
/**
|
|
|
|
* Check if Label Manager is Ready or not.
|
|
|
|
*
|
|
|
|
* @return True if Label Manager is ready, False otherwise
|
|
|
|
*/
|
|
|
|
bool isis_zebra_label_manager_ready(void)
|
|
|
|
{
|
|
|
|
return (zclient_sync->sock > 0);
|
|
|
|
}
|
|
|
|
|
2020-04-10 17:12:48 +02:00
|
|
|
/**
|
|
|
|
* Request Label Range to the Label Manager.
|
|
|
|
*
|
|
|
|
* @param base base label of the label range to request
|
|
|
|
* @param chunk_size size of the label range to request
|
|
|
|
*
|
|
|
|
* @return 0 on success, -1 on failure
|
|
|
|
*/
|
2019-08-04 03:02:37 +02:00
|
|
|
int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
uint32_t start, end;
|
|
|
|
|
2020-06-04 18:03:04 +02:00
|
|
|
if (zclient_sync->sock < 0)
|
|
|
|
return -1;
|
2019-08-04 03:02:37 +02:00
|
|
|
|
|
|
|
ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start,
|
|
|
|
&end);
|
|
|
|
if (ret < 0) {
|
|
|
|
zlog_warn("%s: error getting label range!", __func__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-05-09 11:23:53 +02:00
|
|
|
/**
|
|
|
|
* Request an End.X SID for an IS-IS adjacency.
|
|
|
|
*
|
|
|
|
* @param adj IS-IS Adjacency
|
|
|
|
*/
|
|
|
|
void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj)
|
|
|
|
{
|
|
|
|
struct isis_circuit *circuit = adj->circuit;
|
|
|
|
struct isis_area *area = circuit->area;
|
|
|
|
struct in6_addr nexthop;
|
|
|
|
struct srv6_sid_ctx ctx = {};
|
|
|
|
struct in6_addr sid_value = {};
|
|
|
|
bool ret;
|
|
|
|
|
|
|
|
if (!area || !area->srv6db.srv6_locator)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Determine nexthop IP address */
|
|
|
|
if (!circuit->ipv6_router || !adj->ll_ipv6_count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nexthop = adj->ll_ipv6_addrs[0];
|
|
|
|
|
|
|
|
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X;
|
|
|
|
ctx.nh6 = nexthop;
|
|
|
|
ret = isis_zebra_request_srv6_sid(&ctx, &sid_value,
|
|
|
|
area->srv6db.config.srv6_locator_name);
|
|
|
|
if (!ret) {
|
|
|
|
zlog_err("%s: not allocated new End.X SID for IS-IS area %s",
|
|
|
|
__func__, area->area_tag);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-25 00:41:50 +01:00
|
|
|
static void request_srv6_sids(struct isis_area *area)
|
|
|
|
{
|
|
|
|
struct srv6_sid_ctx ctx = {};
|
|
|
|
struct in6_addr sid_value = {};
|
|
|
|
struct listnode *node;
|
|
|
|
struct isis_adjacency *adj;
|
|
|
|
bool ret;
|
|
|
|
|
|
|
|
if (!area || !area->srv6db.config.enabled || !area->srv6db.srv6_locator)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sr_debug("Requesting SRv6 SIDs for IS-IS area %s", area->area_tag);
|
|
|
|
|
|
|
|
/* Request new SRv6 End SID */
|
|
|
|
ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END;
|
|
|
|
ret = isis_zebra_request_srv6_sid(&ctx, &sid_value,
|
|
|
|
area->srv6db.config.srv6_locator_name);
|
|
|
|
if (!ret) {
|
|
|
|
zlog_err("%s: not allocated new End SID for IS-IS area %s",
|
|
|
|
__func__, area->area_tag);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) {
|
|
|
|
if (adj->ll_ipv6_count > 0)
|
|
|
|
isis_zebra_request_srv6_sid_endx(adj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-10 17:12:48 +02:00
|
|
|
/**
|
|
|
|
* Release Label Range to the Label Manager.
|
|
|
|
*
|
|
|
|
* @param start start of label range to release
|
|
|
|
* @param end end of label range to release
|
|
|
|
*
|
2020-06-04 18:03:04 +02:00
|
|
|
* @return 0 on success, -1 otherwise
|
2020-04-10 17:12:48 +02:00
|
|
|
*/
|
2020-06-04 18:03:04 +02:00
|
|
|
int isis_zebra_release_label_range(uint32_t start, uint32_t end)
|
2019-08-04 03:02:37 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2020-06-04 18:03:04 +02:00
|
|
|
if (zclient_sync->sock < 0)
|
2019-08-04 03:02:37 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
ret = lm_release_label_chunk(zclient_sync, start, end);
|
|
|
|
if (ret < 0) {
|
|
|
|
zlog_warn("%s: error releasing label range!", __func__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-10 17:12:48 +02:00
|
|
|
/**
|
|
|
|
* Connect to the Label Manager.
|
2020-06-04 18:03:04 +02:00
|
|
|
*
|
|
|
|
* @return 0 on success, -1 otherwise
|
2020-04-10 17:12:48 +02:00
|
|
|
*/
|
2020-06-04 18:03:04 +02:00
|
|
|
int isis_zebra_label_manager_connect(void)
|
2019-08-04 03:02:37 +02:00
|
|
|
{
|
|
|
|
/* Connect to label manager. */
|
2020-06-04 18:03:04 +02:00
|
|
|
if (zclient_socket_connect(zclient_sync) < 0) {
|
|
|
|
zlog_warn("%s: failed connecting synchronous zclient!",
|
2019-08-04 03:02:37 +02:00
|
|
|
__func__);
|
2020-06-04 18:03:04 +02:00
|
|
|
return -1;
|
2019-08-04 03:02:37 +02:00
|
|
|
}
|
2020-04-10 17:12:48 +02:00
|
|
|
/* make socket non-blocking */
|
2019-08-04 03:02:37 +02:00
|
|
|
set_nonblocking(zclient_sync->sock);
|
2020-04-10 17:12:48 +02:00
|
|
|
|
|
|
|
/* Send hello to notify zebra this is a synchronous client */
|
2020-11-11 20:14:37 +01:00
|
|
|
if (zclient_send_hello(zclient_sync) == ZCLIENT_SEND_FAILURE) {
|
2020-06-04 18:03:04 +02:00
|
|
|
zlog_warn("%s: failed sending hello for synchronous zclient!",
|
|
|
|
__func__);
|
|
|
|
close(zclient_sync->sock);
|
|
|
|
zclient_sync->sock = -1;
|
|
|
|
return -1;
|
2020-04-10 17:12:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Connect to label manager */
|
2020-06-04 18:03:04 +02:00
|
|
|
if (lm_label_manager_connect(zclient_sync, 0) != 0) {
|
|
|
|
zlog_warn("%s: failed connecting to label manager!", __func__);
|
|
|
|
if (zclient_sync->sock > 0) {
|
|
|
|
close(zclient_sync->sock);
|
|
|
|
zclient_sync->sock = -1;
|
|
|
|
}
|
|
|
|
return -1;
|
2019-08-04 03:02:37 +02:00
|
|
|
}
|
|
|
|
|
2020-06-04 18:03:04 +02:00
|
|
|
sr_debug("ISIS-Sr: Successfully connected to the Label Manager");
|
|
|
|
|
|
|
|
return 0;
|
2019-08-04 03:02:37 +02:00
|
|
|
}
|
|
|
|
|
2020-08-18 09:26:51 +02:00
|
|
|
void isis_zebra_vrf_register(struct isis *isis)
|
|
|
|
{
|
2025-01-23 19:16:11 +01:00
|
|
|
if (!isis_zclient || isis_zclient->sock < 0 || !isis)
|
2020-08-18 09:26:51 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (isis->vrf_id != VRF_UNKNOWN) {
|
|
|
|
if (IS_DEBUG_EVENTS)
|
|
|
|
zlog_debug("%s: Register VRF %s id %u", __func__,
|
|
|
|
isis->name, isis->vrf_id);
|
2025-01-23 19:16:11 +01:00
|
|
|
zclient_send_reg_requests(isis_zclient, isis->vrf_id);
|
2020-08-18 09:26:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-04 20:58:23 +02:00
|
|
|
void isis_zebra_vrf_deregister(struct isis *isis)
|
|
|
|
{
|
2025-01-23 19:16:11 +01:00
|
|
|
if (!isis_zclient || isis_zclient->sock < 0 || !isis)
|
2021-05-04 20:58:23 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (isis->vrf_id != VRF_UNKNOWN) {
|
|
|
|
if (IS_DEBUG_EVENTS)
|
|
|
|
zlog_debug("%s: Deregister VRF %s id %u", __func__,
|
|
|
|
isis->name, isis->vrf_id);
|
2025-01-23 19:16:11 +01:00
|
|
|
zclient_send_dereg_requests(isis_zclient, isis->vrf_id);
|
2021-05-04 20:58:23 +02:00
|
|
|
}
|
|
|
|
}
|
2020-08-18 09:26:51 +02:00
|
|
|
|
*: add VRF ID in the API message header
The API messages are used by zebra to exchange the interfaces, addresses,
routes and router-id information with its clients. To distinguish which
VRF the information belongs to, a new field "VRF ID" is added in the
message header. And hence the message version is increased to 3.
* The new field "VRF ID" in the message header:
Length (2 bytes)
Marker (1 byte)
Version (1 byte)
VRF ID (2 bytes, newly added)
Command (2 bytes)
- Client side:
- zclient_create_header() adds the VRF ID in the message header.
- zclient_read() extracts and validates the VRF ID from the header,
and passes the VRF ID to the callback functions registered to
the API messages.
- All relative functions are appended with a new parameter "vrf_id",
including all the callback functions.
- "vrf_id" is also added to "struct zapi_ipv4" and "struct zapi_ipv6".
Clients need to correctly set the VRF ID when using the API
functions zapi_ipv4_route() and zapi_ipv6_route().
- Till now all messages sent from a client have the default VRF ID
"0" in the header.
- The HELLO message is special, which is used as the heart-beat of
a client, and has no relation with VRF. The VRF ID in the HELLO
message header will always be 0 and ignored by zebra.
- Zebra side:
- zserv_create_header() adds the VRF ID in the message header.
- zebra_client_read() extracts and validates the VRF ID from the
header, and passes the VRF ID to the functions which process
the received messages.
- All relative functions are appended with a new parameter "vrf_id".
* Suppress the messages in a VRF which a client does not care:
Some clients may not care about the information in the VRF X, and
zebra should not send the messages in the VRF X to those clients.
Extra flags are used to indicate which VRF is registered by a client,
and a new message ZEBRA_VRF_UNREGISTER is introduced to let a client
can unregister a VRF when it does not need any information in that
VRF.
A client sends any message other than ZEBRA_VRF_UNREGISTER in a VRF
will automatically register to that VRF.
- lib/vrf:
A new utility "VRF bit-map" is provided to manage the flags for
VRFs, one bit per VRF ID.
- Use vrf_bitmap_init()/vrf_bitmap_free() to initialize/free a
bit-map;
- Use vrf_bitmap_set()/vrf_bitmap_unset() to set/unset a flag
in the given bit-map, corresponding to the given VRF ID;
- Use vrf_bitmap_check() to test whether the flag, in the given
bit-map and for the given VRF ID, is set.
- Client side:
- In "struct zclient", the following flags are changed from
"u_char" to "vrf_bitmap_t":
redist[ZEBRA_ROUTE_MAX]
default_information
These flags are extended for each VRF, and controlled by the
clients themselves (or with the help of zclient_redistribute()
and zclient_redistribute_default()).
- Zebra side:
- In "struct zserv", the following flags are changed from
"u_char" to "vrf_bitmap_t":
redist[ZEBRA_ROUTE_MAX]
redist_default
ifinfo
ridinfo
These flags are extended for each VRF, as the VRF registration
flags. They are maintained on receiving a ZEBRA_XXX_ADD or
ZEBRA_XXX_DELETE message.
When sending an interface/address/route/router-id message in
a VRF to a client, if the corresponding VRF registration flag
is not set, this message will not be dropped by zebra.
- A new function zread_vrf_unregister() is introduced to process
the new command ZEBRA_VRF_UNREGISTER. All the VRF registration
flags are cleared for the requested VRF.
Those clients, who support only the default VRF, will never receive
a message in a non-default VRF, thanks to the filter in zebra.
* New callback for the event of successful connection to zebra:
- zclient_start() is splitted, keeping only the code of connecting
to zebra.
- Now zclient_init()=>zclient_connect()=>zclient_start() operations
are purely dealing with the connection to zbera.
- Once zebra is successfully connected, at the end of zclient_start(),
a new callback is used to inform the client about connection.
- Till now, in the callback of connect-to-zebra event, all clients
send messages to zebra to request the router-id/interface/routes
information in the default VRF.
Of corse in future the client can do anything it wants in this
callback. For example, it may send requests for both default VRF
and some non-default VRFs.
Signed-off-by: Feng Lu <lu.feng@6wind.com>
Reviewed-by: Alain Ritoux <alain.ritoux@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
Conflicts:
lib/zclient.h
lib/zebra.h
zebra/zserv.c
zebra/zserv.h
Conflicts:
bgpd/bgp_nexthop.c
bgpd/bgp_nht.c
bgpd/bgp_zebra.c
isisd/isis_zebra.c
lib/zclient.c
lib/zclient.h
lib/zebra.h
nhrpd/nhrp_interface.c
nhrpd/nhrp_route.c
nhrpd/nhrpd.h
ospf6d/ospf6_zebra.c
ospf6d/ospf6_zebra.h
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
pimd/pim_zebra.c
pimd/pim_zlookup.c
ripd/rip_zebra.c
ripngd/ripng_zebra.c
zebra/redistribute.c
zebra/rt_netlink.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zserv.c
zebra/zserv.h
2014-10-16 03:52:36 +02:00
|
|
|
static void isis_zebra_connected(struct zclient *zclient)
|
|
|
|
{
|
2016-02-12 20:37:33 +01:00
|
|
|
zclient_send_reg_requests(zclient, VRF_DEFAULT);
|
2020-11-26 03:39:09 +01:00
|
|
|
zclient_register_opaque(zclient, LDP_RLFA_LABELS);
|
2021-04-29 00:59:56 +02:00
|
|
|
zclient_register_opaque(zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
|
|
|
|
zclient_register_opaque(zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
|
2021-05-06 13:44:05 +02:00
|
|
|
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
|
2025-02-15 10:39:40 +01:00
|
|
|
isis_srv6_locators_request();
|
*: add VRF ID in the API message header
The API messages are used by zebra to exchange the interfaces, addresses,
routes and router-id information with its clients. To distinguish which
VRF the information belongs to, a new field "VRF ID" is added in the
message header. And hence the message version is increased to 3.
* The new field "VRF ID" in the message header:
Length (2 bytes)
Marker (1 byte)
Version (1 byte)
VRF ID (2 bytes, newly added)
Command (2 bytes)
- Client side:
- zclient_create_header() adds the VRF ID in the message header.
- zclient_read() extracts and validates the VRF ID from the header,
and passes the VRF ID to the callback functions registered to
the API messages.
- All relative functions are appended with a new parameter "vrf_id",
including all the callback functions.
- "vrf_id" is also added to "struct zapi_ipv4" and "struct zapi_ipv6".
Clients need to correctly set the VRF ID when using the API
functions zapi_ipv4_route() and zapi_ipv6_route().
- Till now all messages sent from a client have the default VRF ID
"0" in the header.
- The HELLO message is special, which is used as the heart-beat of
a client, and has no relation with VRF. The VRF ID in the HELLO
message header will always be 0 and ignored by zebra.
- Zebra side:
- zserv_create_header() adds the VRF ID in the message header.
- zebra_client_read() extracts and validates the VRF ID from the
header, and passes the VRF ID to the functions which process
the received messages.
- All relative functions are appended with a new parameter "vrf_id".
* Suppress the messages in a VRF which a client does not care:
Some clients may not care about the information in the VRF X, and
zebra should not send the messages in the VRF X to those clients.
Extra flags are used to indicate which VRF is registered by a client,
and a new message ZEBRA_VRF_UNREGISTER is introduced to let a client
can unregister a VRF when it does not need any information in that
VRF.
A client sends any message other than ZEBRA_VRF_UNREGISTER in a VRF
will automatically register to that VRF.
- lib/vrf:
A new utility "VRF bit-map" is provided to manage the flags for
VRFs, one bit per VRF ID.
- Use vrf_bitmap_init()/vrf_bitmap_free() to initialize/free a
bit-map;
- Use vrf_bitmap_set()/vrf_bitmap_unset() to set/unset a flag
in the given bit-map, corresponding to the given VRF ID;
- Use vrf_bitmap_check() to test whether the flag, in the given
bit-map and for the given VRF ID, is set.
- Client side:
- In "struct zclient", the following flags are changed from
"u_char" to "vrf_bitmap_t":
redist[ZEBRA_ROUTE_MAX]
default_information
These flags are extended for each VRF, and controlled by the
clients themselves (or with the help of zclient_redistribute()
and zclient_redistribute_default()).
- Zebra side:
- In "struct zserv", the following flags are changed from
"u_char" to "vrf_bitmap_t":
redist[ZEBRA_ROUTE_MAX]
redist_default
ifinfo
ridinfo
These flags are extended for each VRF, as the VRF registration
flags. They are maintained on receiving a ZEBRA_XXX_ADD or
ZEBRA_XXX_DELETE message.
When sending an interface/address/route/router-id message in
a VRF to a client, if the corresponding VRF registration flag
is not set, this message will not be dropped by zebra.
- A new function zread_vrf_unregister() is introduced to process
the new command ZEBRA_VRF_UNREGISTER. All the VRF registration
flags are cleared for the requested VRF.
Those clients, who support only the default VRF, will never receive
a message in a non-default VRF, thanks to the filter in zebra.
* New callback for the event of successful connection to zebra:
- zclient_start() is splitted, keeping only the code of connecting
to zebra.
- Now zclient_init()=>zclient_connect()=>zclient_start() operations
are purely dealing with the connection to zbera.
- Once zebra is successfully connected, at the end of zclient_start(),
a new callback is used to inform the client about connection.
- Till now, in the callback of connect-to-zebra event, all clients
send messages to zebra to request the router-id/interface/routes
information in the default VRF.
Of corse in future the client can do anything it wants in this
callback. For example, it may send requests for both default VRF
and some non-default VRFs.
Signed-off-by: Feng Lu <lu.feng@6wind.com>
Reviewed-by: Alain Ritoux <alain.ritoux@6wind.com>
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: Donald Sharp <sharpd@cumulusnetworks.com>
Conflicts:
lib/zclient.h
lib/zebra.h
zebra/zserv.c
zebra/zserv.h
Conflicts:
bgpd/bgp_nexthop.c
bgpd/bgp_nht.c
bgpd/bgp_zebra.c
isisd/isis_zebra.c
lib/zclient.c
lib/zclient.h
lib/zebra.h
nhrpd/nhrp_interface.c
nhrpd/nhrp_route.c
nhrpd/nhrpd.h
ospf6d/ospf6_zebra.c
ospf6d/ospf6_zebra.h
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
pimd/pim_zebra.c
pimd/pim_zlookup.c
ripd/rip_zebra.c
ripngd/ripng_zebra.c
zebra/redistribute.c
zebra/rt_netlink.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zserv.c
zebra/zserv.h
2014-10-16 03:52:36 +02:00
|
|
|
}
|
|
|
|
|
2021-06-22 19:59:02 +02:00
|
|
|
/**
|
|
|
|
* Register / unregister Link State ZAPI Opaque Message
|
|
|
|
*
|
|
|
|
* @param up True to register, false to unregister
|
|
|
|
*
|
|
|
|
* @return 0 if success, -1 otherwise
|
|
|
|
*/
|
|
|
|
int isis_zebra_ls_register(bool up)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (up)
|
2025-01-23 19:16:11 +01:00
|
|
|
rc = ls_register(isis_zclient, true);
|
2021-06-22 19:59:02 +02:00
|
|
|
else
|
2025-01-23 19:16:11 +01:00
|
|
|
rc = ls_unregister(isis_zclient, true);
|
2021-06-22 19:59:02 +02:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-07-22 20:32:35 +02:00
|
|
|
/*
|
|
|
|
* opaque messages between processes
|
|
|
|
*/
|
|
|
|
static int isis_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
|
|
|
|
{
|
|
|
|
struct stream *s;
|
|
|
|
struct zapi_opaque_msg info;
|
2021-06-22 19:59:02 +02:00
|
|
|
struct zapi_opaque_reg_info dst;
|
2020-07-22 20:32:35 +02:00
|
|
|
struct ldp_igp_sync_if_state state;
|
|
|
|
struct ldp_igp_sync_announce announce;
|
2020-11-26 03:39:09 +01:00
|
|
|
struct zapi_rlfa_response rlfa;
|
2020-07-22 20:32:35 +02:00
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
s = zclient->ibuf;
|
|
|
|
if (zclient_opaque_decode(s, &info) != 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
switch (info.type) {
|
2021-06-22 19:59:02 +02:00
|
|
|
case LINK_STATE_SYNC:
|
2023-06-27 22:32:54 +02:00
|
|
|
dst.proto = info.src_proto;
|
|
|
|
dst.instance = info.src_instance;
|
|
|
|
dst.session_id = info.src_session_id;
|
2021-06-22 19:59:02 +02:00
|
|
|
dst.type = LINK_STATE_SYNC;
|
|
|
|
ret = isis_te_sync_ted(dst);
|
|
|
|
break;
|
2020-07-22 20:32:35 +02:00
|
|
|
case LDP_IGP_SYNC_IF_STATE_UPDATE:
|
|
|
|
STREAM_GET(&state, s, sizeof(state));
|
|
|
|
ret = isis_ldp_sync_state_update(state);
|
|
|
|
break;
|
|
|
|
case LDP_IGP_SYNC_ANNOUNCE_UPDATE:
|
|
|
|
STREAM_GET(&announce, s, sizeof(announce));
|
|
|
|
ret = isis_ldp_sync_announce_update(announce);
|
|
|
|
break;
|
2020-11-26 03:39:09 +01:00
|
|
|
case LDP_RLFA_LABELS:
|
|
|
|
STREAM_GET(&rlfa, s, sizeof(rlfa));
|
|
|
|
isis_rlfa_process_ldp_response(&rlfa);
|
|
|
|
break;
|
2020-07-22 20:32:35 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
stream_failure:
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-12-08 15:44:27 +01:00
|
|
|
static int isis_zebra_client_close_notify(ZAPI_CALLBACK_ARGS)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
struct zapi_client_close_info info;
|
|
|
|
|
|
|
|
if (zapi_client_close_notify_decode(zclient->ibuf, &info) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
isis_ldp_sync_handle_client_close(&info);
|
2020-11-26 03:39:09 +01:00
|
|
|
isis_ldp_rlfa_handle_client_close(&info);
|
2020-12-08 15:44:27 +01:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-06-03 08:39:33 +02:00
|
|
|
/**
|
|
|
|
* Send SRv6 SID to ZEBRA for installation or deletion.
|
|
|
|
*
|
|
|
|
* @param cmd ZEBRA_ROUTE_ADD or ZEBRA_ROUTE_DELETE
|
|
|
|
* @param sid SRv6 SID to install or delete
|
|
|
|
* @param prefixlen Prefix length
|
|
|
|
* @param oif Outgoing interface
|
|
|
|
* @param action SID action
|
|
|
|
* @param context SID context
|
|
|
|
*/
|
|
|
|
static void isis_zebra_send_localsid(int cmd, const struct in6_addr *sid,
|
|
|
|
uint16_t prefixlen, ifindex_t oif,
|
|
|
|
enum seg6local_action_t action,
|
|
|
|
const struct seg6local_context *context)
|
|
|
|
{
|
|
|
|
struct prefix_ipv6 p = {};
|
|
|
|
struct zapi_route api = {};
|
|
|
|
struct zapi_nexthop *znh;
|
|
|
|
|
|
|
|
if (cmd != ZEBRA_ROUTE_ADD && cmd != ZEBRA_ROUTE_DELETE) {
|
|
|
|
flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
|
|
|
|
__func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prefixlen > IPV6_MAX_BITLEN) {
|
|
|
|
flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong prefixlen %u",
|
|
|
|
__func__, prefixlen);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sr_debug(" |- %s SRv6 SID %pI6 behavior %s",
|
|
|
|
cmd == ZEBRA_ROUTE_ADD ? "Add" : "Delete", sid,
|
|
|
|
seg6local_action2str(action));
|
|
|
|
|
|
|
|
p.family = AF_INET6;
|
|
|
|
p.prefixlen = prefixlen;
|
|
|
|
p.prefix = *sid;
|
|
|
|
|
|
|
|
api.vrf_id = VRF_DEFAULT;
|
|
|
|
api.type = PROTO_TYPE;
|
|
|
|
api.instance = 0;
|
|
|
|
api.safi = SAFI_UNICAST;
|
|
|
|
memcpy(&api.prefix, &p, sizeof(p));
|
|
|
|
|
|
|
|
if (cmd == ZEBRA_ROUTE_DELETE)
|
2025-01-23 19:16:11 +01:00
|
|
|
return (void)zclient_route_send(ZEBRA_ROUTE_DELETE, isis_zclient,
|
2023-06-03 08:39:33 +02:00
|
|
|
&api);
|
|
|
|
|
|
|
|
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
|
|
|
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
|
|
|
|
|
|
|
|
znh = &api.nexthops[0];
|
|
|
|
|
|
|
|
memset(znh, 0, sizeof(*znh));
|
|
|
|
|
|
|
|
znh->type = NEXTHOP_TYPE_IFINDEX;
|
|
|
|
znh->ifindex = oif;
|
|
|
|
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_SEG6LOCAL);
|
|
|
|
znh->seg6local_action = action;
|
|
|
|
memcpy(&znh->seg6local_ctx, context, sizeof(struct seg6local_context));
|
|
|
|
|
|
|
|
api.nexthop_num = 1;
|
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
zclient_route_send(ZEBRA_ROUTE_ADD, isis_zclient, &api);
|
2023-06-03 08:39:33 +02:00
|
|
|
}
|
|
|
|
|
2023-02-22 11:18:46 +01:00
|
|
|
/**
|
|
|
|
* Install SRv6 SID in the forwarding plane through Zebra.
|
|
|
|
*
|
|
|
|
* @param area IS-IS area
|
|
|
|
* @param sid SRv6 SID
|
|
|
|
*/
|
|
|
|
void isis_zebra_srv6_sid_install(struct isis_area *area,
|
|
|
|
struct isis_srv6_sid *sid)
|
|
|
|
{
|
|
|
|
enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
|
|
|
|
uint16_t prefixlen = IPV6_MAX_BITLEN;
|
|
|
|
struct seg6local_context ctx = {};
|
|
|
|
struct interface *ifp;
|
|
|
|
|
|
|
|
if (!area || !sid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sr_debug("ISIS-SRv6 (%s): setting SRv6 SID %pI6", area->area_tag,
|
|
|
|
&sid->sid);
|
|
|
|
|
|
|
|
switch (sid->behavior) {
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END:
|
|
|
|
action = ZEBRA_SEG6_LOCAL_ACTION_END;
|
|
|
|
prefixlen = IPV6_MAX_BITLEN;
|
|
|
|
break;
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID:
|
|
|
|
action = ZEBRA_SEG6_LOCAL_ACTION_END;
|
|
|
|
prefixlen = sid->locator->block_bits_length +
|
|
|
|
sid->locator->node_bits_length;
|
|
|
|
SET_SRV6_FLV_OP(ctx.flv.flv_ops,
|
|
|
|
ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID);
|
|
|
|
ctx.flv.lcblock_len = sid->locator->block_bits_length;
|
|
|
|
ctx.flv.lcnode_func_len = sid->locator->node_bits_length;
|
|
|
|
break;
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_RESERVED:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT6:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT4:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT46:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_OPAQUE:
|
2025-01-30 09:14:00 +01:00
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP_USD:
|
2023-02-22 11:18:46 +01:00
|
|
|
default:
|
|
|
|
zlog_err(
|
|
|
|
"ISIS-SRv6 (%s): unsupported SRv6 endpoint behavior %u",
|
|
|
|
area->area_tag, sid->behavior);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Attach the SID to the SRv6 interface */
|
2023-09-03 08:54:57 +02:00
|
|
|
ifp = if_lookup_by_name(area->srv6db.config.srv6_ifname, VRF_DEFAULT);
|
2023-02-22 11:18:46 +01:00
|
|
|
if (!ifp) {
|
|
|
|
zlog_warn(
|
|
|
|
"Failed to install SRv6 SID %pI6: %s interface not found",
|
2023-09-03 08:54:57 +02:00
|
|
|
&sid->sid, area->srv6db.config.srv6_ifname);
|
2023-02-22 11:18:46 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send the SID to zebra */
|
|
|
|
isis_zebra_send_localsid(ZEBRA_ROUTE_ADD, &sid->sid, prefixlen,
|
|
|
|
ifp->ifindex, action, &ctx);
|
|
|
|
}
|
|
|
|
|
2023-02-22 11:19:28 +01:00
|
|
|
/**
|
|
|
|
* Uninstall SRv6 SID from the forwarding plane through Zebra.
|
|
|
|
*
|
|
|
|
* @param area IS-IS area
|
|
|
|
* @param sid SRv6 SID
|
|
|
|
*/
|
|
|
|
void isis_zebra_srv6_sid_uninstall(struct isis_area *area,
|
|
|
|
struct isis_srv6_sid *sid)
|
|
|
|
{
|
|
|
|
enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
|
|
|
|
struct interface *ifp;
|
|
|
|
uint16_t prefixlen = IPV6_MAX_BITLEN;
|
|
|
|
|
|
|
|
if (!area || !sid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
sr_debug("ISIS-SRv6 (%s): delete SID %pI6", area->area_tag, &sid->sid);
|
|
|
|
|
|
|
|
switch (sid->behavior) {
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END:
|
|
|
|
prefixlen = IPV6_MAX_BITLEN;
|
|
|
|
break;
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID:
|
|
|
|
prefixlen = sid->locator->block_bits_length +
|
|
|
|
sid->locator->node_bits_length;
|
|
|
|
break;
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_RESERVED:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT6:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT4:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT46:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_OPAQUE:
|
2025-01-30 09:14:00 +01:00
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP_USD:
|
2023-02-22 11:19:28 +01:00
|
|
|
default:
|
|
|
|
zlog_err(
|
|
|
|
"ISIS-SRv6 (%s): unsupported SRv6 endpoint behavior %u",
|
|
|
|
area->area_tag, sid->behavior);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The SID is attached to the SRv6 interface */
|
2023-09-03 08:54:57 +02:00
|
|
|
ifp = if_lookup_by_name(area->srv6db.config.srv6_ifname, VRF_DEFAULT);
|
2023-02-22 11:19:28 +01:00
|
|
|
if (!ifp) {
|
|
|
|
zlog_warn("%s interface not found: nothing to uninstall",
|
2023-09-03 08:54:57 +02:00
|
|
|
area->srv6db.config.srv6_ifname);
|
2023-02-22 11:19:28 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send delete request to zebra */
|
|
|
|
isis_zebra_send_localsid(ZEBRA_ROUTE_DELETE, &sid->sid, prefixlen,
|
|
|
|
ifp->ifindex, action, NULL);
|
|
|
|
}
|
|
|
|
|
2023-06-03 08:41:50 +02:00
|
|
|
void isis_zebra_srv6_adj_sid_install(struct srv6_adjacency *sra)
|
|
|
|
{
|
|
|
|
enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
|
|
|
|
struct seg6local_context ctx = {};
|
|
|
|
uint16_t prefixlen = IPV6_MAX_BITLEN;
|
|
|
|
struct interface *ifp;
|
2023-09-15 12:25:50 +02:00
|
|
|
struct isis_circuit *circuit;
|
|
|
|
struct isis_area *area;
|
2023-06-03 08:41:50 +02:00
|
|
|
|
|
|
|
if (!sra)
|
|
|
|
return;
|
|
|
|
|
2023-09-15 12:25:50 +02:00
|
|
|
circuit = sra->adj->circuit;
|
|
|
|
area = circuit->area;
|
|
|
|
|
2023-06-03 08:41:50 +02:00
|
|
|
sr_debug("ISIS-SRv6 (%s): setting adjacency SID %pI6", area->area_tag,
|
|
|
|
&sra->sid);
|
|
|
|
|
|
|
|
switch (sra->behavior) {
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X:
|
|
|
|
action = ZEBRA_SEG6_LOCAL_ACTION_END_X;
|
|
|
|
prefixlen = IPV6_MAX_BITLEN;
|
|
|
|
ctx.nh6 = sra->nexthop;
|
|
|
|
break;
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:
|
|
|
|
action = ZEBRA_SEG6_LOCAL_ACTION_END_X;
|
|
|
|
prefixlen = sra->locator->block_bits_length +
|
|
|
|
sra->locator->node_bits_length +
|
|
|
|
sra->locator->function_bits_length;
|
|
|
|
ctx.nh6 = sra->nexthop;
|
|
|
|
SET_SRV6_FLV_OP(ctx.flv.flv_ops,
|
|
|
|
ZEBRA_SEG6_LOCAL_FLV_OP_NEXT_CSID);
|
|
|
|
ctx.flv.lcblock_len = sra->locator->block_bits_length;
|
|
|
|
ctx.flv.lcnode_func_len = sra->locator->node_bits_length;
|
|
|
|
break;
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_RESERVED:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT6:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT4:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT46:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_OPAQUE:
|
2025-01-30 09:14:00 +01:00
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP_USD:
|
2023-06-03 08:41:50 +02:00
|
|
|
default:
|
|
|
|
zlog_err(
|
|
|
|
"ISIS-SRv6 (%s): unsupported SRv6 endpoint behavior %u",
|
|
|
|
area->area_tag, sra->behavior);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifp = sra->adj->circuit->interface;
|
|
|
|
|
|
|
|
isis_zebra_send_localsid(ZEBRA_ROUTE_ADD, &sra->sid, prefixlen,
|
|
|
|
ifp->ifindex, action, &ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra)
|
|
|
|
{
|
|
|
|
enum seg6local_action_t action = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
|
|
|
|
struct interface *ifp;
|
|
|
|
uint16_t prefixlen = IPV6_MAX_BITLEN;
|
2023-09-15 12:30:39 +02:00
|
|
|
struct isis_circuit *circuit;
|
|
|
|
struct isis_area *area;
|
2023-06-03 08:41:50 +02:00
|
|
|
|
|
|
|
if (!sra)
|
|
|
|
return;
|
|
|
|
|
2023-09-15 12:30:39 +02:00
|
|
|
circuit = sra->adj->circuit;
|
|
|
|
area = circuit->area;
|
|
|
|
|
2023-06-03 08:41:50 +02:00
|
|
|
switch (sra->behavior) {
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X:
|
|
|
|
prefixlen = IPV6_MAX_BITLEN;
|
|
|
|
break;
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID:
|
|
|
|
prefixlen = sra->locator->block_bits_length +
|
|
|
|
sra->locator->node_bits_length +
|
|
|
|
sra->locator->function_bits_length;
|
|
|
|
break;
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_RESERVED:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT6:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT4:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT46:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_OPAQUE:
|
2025-01-30 09:14:00 +01:00
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_PSP_USD:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP:
|
|
|
|
case SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID_PSP_USD:
|
2023-06-03 08:41:50 +02:00
|
|
|
default:
|
|
|
|
zlog_err(
|
|
|
|
"ISIS-SRv6 (%s): unsupported SRv6 endpoint behavior %u",
|
|
|
|
area->area_tag, sra->behavior);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifp = sra->adj->circuit->interface;
|
|
|
|
|
|
|
|
sr_debug("ISIS-SRv6 (%s): delete End.X SID %pI6", area->area_tag,
|
|
|
|
&sra->sid);
|
|
|
|
|
|
|
|
isis_zebra_send_localsid(ZEBRA_ROUTE_DELETE, &sra->sid, prefixlen,
|
|
|
|
ifp->ifindex, action, NULL);
|
|
|
|
}
|
|
|
|
|
2024-03-25 00:41:50 +01:00
|
|
|
/**
|
|
|
|
* Internal function to process an SRv6 locator
|
|
|
|
*
|
|
|
|
* @param locator The locator to be processed
|
|
|
|
*/
|
|
|
|
static int isis_zebra_process_srv6_locator_internal(struct srv6_locator *locator)
|
|
|
|
{
|
|
|
|
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
|
|
|
|
struct isis_area *area;
|
|
|
|
struct listnode *node;
|
|
|
|
|
|
|
|
if (!isis || !locator)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
zlog_info("%s: Received SRv6 locator %s %pFX, loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u",
|
|
|
|
__func__, locator->name, &locator->prefix,
|
|
|
|
locator->block_bits_length, locator->node_bits_length,
|
|
|
|
locator->function_bits_length, locator->argument_bits_length);
|
|
|
|
|
|
|
|
/* Walk through all areas of the ISIS instance */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
|
|
|
|
/*
|
|
|
|
* Check if the IS-IS area is configured to use the received
|
|
|
|
* locator
|
|
|
|
*/
|
|
|
|
if (strncmp(area->srv6db.config.srv6_locator_name, locator->name,
|
|
|
|
sizeof(area->srv6db.config.srv6_locator_name)) != 0) {
|
|
|
|
zlog_err("%s: SRv6 Locator name unmatch %s:%s",
|
|
|
|
__func__, area->srv6db.config.srv6_locator_name,
|
|
|
|
locator->name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sr_debug("SRv6 locator (locator %s, prefix %pFX) set for IS-IS area %s",
|
|
|
|
locator->name, &locator->prefix, area->area_tag);
|
|
|
|
|
|
|
|
/* Store the locator in the IS-IS area */
|
|
|
|
area->srv6db.srv6_locator = srv6_locator_alloc(locator->name);
|
|
|
|
srv6_locator_copy(area->srv6db.srv6_locator, locator);
|
|
|
|
|
|
|
|
/* Request SIDs from the locator */
|
|
|
|
request_srv6_sids(area);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-02-09 19:09:04 +01:00
|
|
|
/**
|
|
|
|
* Callback to process an SRv6 locator received from SRv6 Manager (zebra).
|
|
|
|
*
|
|
|
|
* @result 0 on success, -1 otherwise
|
|
|
|
*/
|
|
|
|
static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS)
|
|
|
|
{
|
|
|
|
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
|
|
|
|
struct srv6_locator loc = {};
|
|
|
|
|
isisd: fix crash when configuring srv6 locator without isis instance
After the ISIS daemon is launched, the configuration of an srv6
locator in zebra triggers a crash:
> #4 0x00007f1f0ea980f3 in core_handler (signo=11, siginfo=0x7ffdb750de70, context=0x7ffdb750dd40)
> at /build/make-pkg/output/_packages/cp-routing/src/lib/sigevent.c:262
> #5 <signal handler called>
> #6 0x00005651a05783ef in isis_zebra_process_srv6_locator_add (cmd=117, zclient=0x5651a21d9bd0, length=25, vrf_id=0)
> at /build/make-pkg/output/_packages/cp-routing/src/isisd/isis_zebra.c:1258
> #7 0x00007f1f0ead5ac9 in zclient_read (thread=0x7ffdb750e750) at /build/make-pkg/output/_packages/cp-routing/src/lib/zclient.c:4246
> #8 0x00007f1f0eab19d4 in thread_call (thread=0x7ffdb750e750) at /build/make-pkg/output/_packages/cp-routing/src/lib/thread.c:1825
> #9 0x00007f1f0ea4862e in frr_run (master=0x5651a1f65a40) at /build/make-pkg/output/_packages/cp-routing/src/lib/libfrr.c:1155
> #10 0x00005651a051131a in main (argc=5, argv=0x7ffdb750e998, envp=0x7ffdb750e9c8)
> at /build/make-pkg/output/_packages/cp-routing/src/isisd/isis_main.c:282
> (gdb) f 6
> #6 0x00005651a05783ef in isis_zebra_process_srv6_locator_add (cmd=117, zclient=0x5651a21d9bd0, length=25, vrf_id=0)
> at /build/make-pkg/output/_packages/cp-routing/src/isisd/isis_zebra.c:1258
> (gdb) print isis
> $1 = (struct isis *) 0x0
> (gdb) print isis->area_list
> Cannot access memory at address 0x28
The isis pointer is NULL, because no instances have already been
configured on the ISIS instance.
Fix this by checking that there is any isis instance available when
zebra hooks related to srv6 are received.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-09-20 13:58:29 +02:00
|
|
|
if (!isis)
|
|
|
|
return -1;
|
|
|
|
|
2023-02-09 19:09:04 +01:00
|
|
|
/* Decode the SRv6 locator */
|
|
|
|
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2024-03-25 00:41:50 +01:00
|
|
|
return isis_zebra_process_srv6_locator_internal(&loc);
|
2023-02-09 19:09:04 +01:00
|
|
|
}
|
|
|
|
|
2023-02-09 19:11:05 +01:00
|
|
|
/**
|
|
|
|
* Callback to process a notification from SRv6 Manager (zebra) of an SRv6
|
|
|
|
* locator deleted.
|
|
|
|
*
|
|
|
|
* @result 0 on success, -1 otherwise
|
|
|
|
*/
|
|
|
|
static int isis_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
|
|
|
|
{
|
|
|
|
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
|
|
|
|
struct srv6_locator loc = {};
|
|
|
|
struct isis_area *area;
|
|
|
|
struct listnode *node, *nnode;
|
|
|
|
struct srv6_locator_chunk *chunk;
|
2023-05-30 18:55:44 +02:00
|
|
|
struct isis_srv6_sid *sid;
|
|
|
|
struct srv6_adjacency *sra;
|
2023-02-09 19:11:05 +01:00
|
|
|
|
isisd: fix crash when configuring srv6 locator without isis instance
After the ISIS daemon is launched, the configuration of an srv6
locator in zebra triggers a crash:
> #4 0x00007f1f0ea980f3 in core_handler (signo=11, siginfo=0x7ffdb750de70, context=0x7ffdb750dd40)
> at /build/make-pkg/output/_packages/cp-routing/src/lib/sigevent.c:262
> #5 <signal handler called>
> #6 0x00005651a05783ef in isis_zebra_process_srv6_locator_add (cmd=117, zclient=0x5651a21d9bd0, length=25, vrf_id=0)
> at /build/make-pkg/output/_packages/cp-routing/src/isisd/isis_zebra.c:1258
> #7 0x00007f1f0ead5ac9 in zclient_read (thread=0x7ffdb750e750) at /build/make-pkg/output/_packages/cp-routing/src/lib/zclient.c:4246
> #8 0x00007f1f0eab19d4 in thread_call (thread=0x7ffdb750e750) at /build/make-pkg/output/_packages/cp-routing/src/lib/thread.c:1825
> #9 0x00007f1f0ea4862e in frr_run (master=0x5651a1f65a40) at /build/make-pkg/output/_packages/cp-routing/src/lib/libfrr.c:1155
> #10 0x00005651a051131a in main (argc=5, argv=0x7ffdb750e998, envp=0x7ffdb750e9c8)
> at /build/make-pkg/output/_packages/cp-routing/src/isisd/isis_main.c:282
> (gdb) f 6
> #6 0x00005651a05783ef in isis_zebra_process_srv6_locator_add (cmd=117, zclient=0x5651a21d9bd0, length=25, vrf_id=0)
> at /build/make-pkg/output/_packages/cp-routing/src/isisd/isis_zebra.c:1258
> (gdb) print isis
> $1 = (struct isis *) 0x0
> (gdb) print isis->area_list
> Cannot access memory at address 0x28
The isis pointer is NULL, because no instances have already been
configured on the ISIS instance.
Fix this by checking that there is any isis instance available when
zebra hooks related to srv6 are received.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
2023-09-20 13:58:29 +02:00
|
|
|
if (!isis)
|
|
|
|
return -1;
|
|
|
|
|
2023-02-09 19:11:05 +01:00
|
|
|
/* Decode the received zebra message */
|
|
|
|
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
sr_debug(
|
|
|
|
"SRv6 locator deleted in zebra: name %s, "
|
|
|
|
"prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u",
|
|
|
|
loc.name, &loc.prefix, loc.block_bits_length,
|
|
|
|
loc.node_bits_length, loc.function_bits_length,
|
|
|
|
loc.argument_bits_length);
|
|
|
|
|
|
|
|
/* Walk through all areas of the ISIS instance */
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
|
|
|
|
if (strncmp(area->srv6db.config.srv6_locator_name, loc.name,
|
|
|
|
sizeof(area->srv6db.config.srv6_locator_name)) != 0)
|
|
|
|
continue;
|
|
|
|
|
2023-05-30 18:55:44 +02:00
|
|
|
/* Delete SRv6 SIDs */
|
|
|
|
for (ALL_LIST_ELEMENTS(area->srv6db.srv6_sids, node, nnode,
|
|
|
|
sid)) {
|
|
|
|
|
|
|
|
sr_debug(
|
|
|
|
"Deleting SRv6 SID (locator %s, sid %pI6) from IS-IS area %s",
|
|
|
|
area->srv6db.config.srv6_locator_name,
|
|
|
|
&sid->sid, area->area_tag);
|
|
|
|
|
|
|
|
/* Uninstall the SRv6 SID from the forwarding plane
|
|
|
|
* through Zebra */
|
|
|
|
isis_zebra_srv6_sid_uninstall(area, sid);
|
|
|
|
|
|
|
|
listnode_delete(area->srv6db.srv6_sids, sid);
|
|
|
|
isis_srv6_sid_free(sid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Uninstall all local Adjacency-SIDs. */
|
|
|
|
for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode,
|
|
|
|
sra))
|
|
|
|
srv6_endx_sid_del(sra);
|
|
|
|
|
2023-02-09 19:11:05 +01:00
|
|
|
/* Free the SRv6 locator chunks */
|
|
|
|
for (ALL_LIST_ELEMENTS(area->srv6db.srv6_locator_chunks, node,
|
|
|
|
nnode, chunk)) {
|
|
|
|
if (prefix_match((struct prefix *)&loc.prefix,
|
|
|
|
(struct prefix *)&chunk->prefix)) {
|
|
|
|
listnode_delete(
|
|
|
|
area->srv6db.srv6_locator_chunks,
|
|
|
|
chunk);
|
|
|
|
srv6_locator_chunk_free(&chunk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-09 09:17:49 +02:00
|
|
|
srv6_locator_free(area->srv6db.srv6_locator);
|
|
|
|
area->srv6db.srv6_locator = NULL;
|
|
|
|
|
2023-02-09 19:11:05 +01:00
|
|
|
/* Regenerate LSPs to advertise that the locator no longer
|
|
|
|
* exists */
|
|
|
|
lsp_regenerate_schedule(area, area->is_type, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-02-02 12:54:48 +01:00
|
|
|
/**
|
|
|
|
* Request an SRv6 locator chunk to the SRv6 Manager (zebra) asynchronously.
|
|
|
|
*
|
|
|
|
* @param locator_name Name of SRv6 locator
|
|
|
|
*
|
|
|
|
* @result 0 on success, -1 otherwise
|
|
|
|
*/
|
|
|
|
int isis_zebra_srv6_manager_get_locator_chunk(const char *name)
|
|
|
|
{
|
2025-01-23 19:16:11 +01:00
|
|
|
return srv6_manager_get_locator_chunk(isis_zclient, name);
|
2023-02-02 12:54:48 +01:00
|
|
|
}
|
|
|
|
|
2023-02-02 13:04:33 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Release an SRv6 locator chunk.
|
|
|
|
*
|
|
|
|
* @param locator_name Name of SRv6 locator
|
|
|
|
*
|
|
|
|
* @result 0 on success, -1 otherwise
|
|
|
|
*/
|
|
|
|
int isis_zebra_srv6_manager_release_locator_chunk(const char *name)
|
|
|
|
{
|
2025-01-23 19:16:11 +01:00
|
|
|
return srv6_manager_release_locator_chunk(isis_zclient, name);
|
2023-02-02 13:04:33 +01:00
|
|
|
}
|
|
|
|
|
2024-03-23 19:40:13 +01:00
|
|
|
/**
|
|
|
|
* Ask the SRv6 Manager (zebra) about a specific locator
|
|
|
|
*
|
|
|
|
* @param name Locator name
|
|
|
|
* @return 0 on success, -1 otherwise
|
|
|
|
*/
|
|
|
|
int isis_zebra_srv6_manager_get_locator(const char *name)
|
|
|
|
{
|
|
|
|
if (!name)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send the Get Locator request to the SRv6 Manager and return the
|
|
|
|
* result
|
|
|
|
*/
|
2025-01-23 19:16:11 +01:00
|
|
|
return srv6_manager_get_locator(isis_zclient, name);
|
2024-03-23 19:40:13 +01:00
|
|
|
}
|
|
|
|
|
2024-05-09 11:23:53 +02:00
|
|
|
/**
|
|
|
|
* Ask the SRv6 Manager (zebra) to allocate a SID.
|
|
|
|
*
|
|
|
|
* Optionally, it is possible to provide an IPv6 address (sid_value parameter).
|
|
|
|
*
|
|
|
|
* When sid_value is provided, the SRv6 Manager allocates the requested SID
|
|
|
|
* address, if the request can be satisfied (explicit allocation).
|
|
|
|
*
|
|
|
|
* When sid_value is not provided, the SRv6 Manager allocates any available SID
|
|
|
|
* from the provided locator (dynamic allocation).
|
|
|
|
*
|
|
|
|
* @param ctx Context to be associated with the request SID
|
|
|
|
* @param sid_value IPv6 address to be associated with the requested SID (optional)
|
|
|
|
* @param locator_name Name of the locator from which the SID must be allocated
|
|
|
|
*/
|
|
|
|
bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx,
|
|
|
|
struct in6_addr *sid_value,
|
|
|
|
const char *locator_name)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!ctx || !locator_name)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send the Get SRv6 SID request to the SRv6 Manager and check the
|
|
|
|
* result
|
|
|
|
*/
|
2025-01-23 19:16:11 +01:00
|
|
|
ret = srv6_manager_get_sid(isis_zclient, ctx, sid_value, locator_name, NULL);
|
2024-05-09 11:23:53 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
zlog_warn("%s: error getting SRv6 SID!", __func__);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Ask the SRv6 Manager (zebra) to release a previously allocated SID.
|
|
|
|
*
|
|
|
|
* This function is used to tell the SRv6 Manager that IS-IS no longer intends
|
|
|
|
* to use the SID.
|
|
|
|
*
|
|
|
|
* @param ctx Context to be associated with the SID to be released
|
|
|
|
*/
|
|
|
|
void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!ctx)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send the Release SRv6 SID request to the SRv6 Manager and check the
|
|
|
|
* result
|
|
|
|
*/
|
2025-01-23 19:16:11 +01:00
|
|
|
ret = srv6_manager_release_sid(isis_zclient, ctx);
|
2024-05-09 11:23:53 +02:00
|
|
|
if (ret < 0) {
|
|
|
|
zlog_warn("%s: error releasing SRv6 SID!", __func__);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-09 11:51:16 +02:00
|
|
|
static int isis_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS)
|
|
|
|
{
|
|
|
|
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
|
|
|
|
struct srv6_sid_ctx ctx;
|
|
|
|
struct in6_addr sid_addr;
|
|
|
|
enum zapi_srv6_sid_notify note;
|
|
|
|
uint32_t sid_func;
|
|
|
|
struct isis_area *area;
|
|
|
|
struct listnode *node, *nnode, *n;
|
|
|
|
char buf[256];
|
|
|
|
struct srv6_locator *locator;
|
|
|
|
struct prefix_ipv6 tmp_prefix;
|
|
|
|
struct srv6_adjacency *sra;
|
|
|
|
enum srv6_endpoint_behavior_codepoint behavior;
|
|
|
|
struct isis_srv6_sid *sid;
|
|
|
|
struct isis_adjacency *adj;
|
|
|
|
|
|
|
|
if (!isis)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Decode the received notification message */
|
|
|
|
if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr,
|
2024-06-08 07:15:47 +02:00
|
|
|
&sid_func, NULL, ¬e, NULL)) {
|
2024-05-09 11:51:16 +02:00
|
|
|
zlog_err("%s : error in msg decode", __func__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sr_debug("%s: received SRv6 SID notify: ctx %s sid_value %pI6 sid_func %u note %s",
|
|
|
|
__func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx), &sid_addr,
|
|
|
|
sid_func, zapi_srv6_sid_notify2str(note));
|
|
|
|
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
|
|
|
|
if (!area->srv6db.config.enabled || !area->srv6db.srv6_locator)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
locator = area->srv6db.srv6_locator;
|
|
|
|
|
|
|
|
/* Verify that the received SID belongs to the configured locator */
|
|
|
|
if (note == ZAPI_SRV6_SID_ALLOCATED) {
|
|
|
|
tmp_prefix.family = AF_INET6;
|
|
|
|
tmp_prefix.prefixlen = IPV6_MAX_BITLEN;
|
|
|
|
tmp_prefix.prefix = sid_addr;
|
|
|
|
|
|
|
|
if (!prefix_match((struct prefix *)&locator->prefix,
|
|
|
|
(struct prefix *)&tmp_prefix)) {
|
|
|
|
sr_debug("%s : ignoring SRv6 SID notify: locator (area %s) does not match",
|
|
|
|
__func__, area->area_tag);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Handle notification */
|
|
|
|
switch (note) {
|
|
|
|
case ZAPI_SRV6_SID_ALLOCATED:
|
|
|
|
sr_debug("SRv6 SID %pI6 %s ALLOCATED", &sid_addr,
|
|
|
|
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
|
|
|
|
|
|
|
|
if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) {
|
|
|
|
/* Remove old End SIDs, if any */
|
|
|
|
for (ALL_LIST_ELEMENTS(area->srv6db.srv6_sids,
|
|
|
|
node, nnode, sid)) {
|
|
|
|
isis_zebra_srv6_sid_uninstall(area, sid);
|
|
|
|
listnode_delete(area->srv6db.srv6_sids,
|
|
|
|
sid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate new SRv6 End SID */
|
|
|
|
behavior =
|
|
|
|
(CHECK_FLAG(locator->flags,
|
|
|
|
SRV6_LOCATOR_USID))
|
|
|
|
? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID
|
|
|
|
: SRV6_ENDPOINT_BEHAVIOR_END;
|
|
|
|
sid = isis_srv6_sid_alloc(area,
|
|
|
|
area->srv6db
|
|
|
|
.srv6_locator,
|
|
|
|
behavior, &sid_addr);
|
|
|
|
if (!sid) {
|
|
|
|
zlog_warn("%s: isis_srv6_sid_alloc failed",
|
|
|
|
__func__);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Install the new SRv6 End SID in the forwarding plane through
|
|
|
|
* Zebra
|
|
|
|
*/
|
|
|
|
isis_zebra_srv6_sid_install(area, sid);
|
|
|
|
|
|
|
|
/* Store the SID */
|
|
|
|
listnode_add(area->srv6db.srv6_sids, sid);
|
|
|
|
|
|
|
|
} else if (ctx.behavior ==
|
|
|
|
ZEBRA_SEG6_LOCAL_ACTION_END_X) {
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(area->adjacency_list,
|
|
|
|
n, adj)) {
|
|
|
|
/* Check if the End.X SID is for this adjacecny */
|
|
|
|
if (adj->ll_ipv6_count == 0 ||
|
|
|
|
memcmp(&adj->ll_ipv6_addrs[0],
|
|
|
|
&ctx.nh6,
|
|
|
|
sizeof(struct in6_addr)) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Remove old End.X SIDs, if any */
|
|
|
|
for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids,
|
|
|
|
node, nnode, sra))
|
|
|
|
srv6_endx_sid_del(sra);
|
|
|
|
|
|
|
|
/* Allocate new End.X SID for the adjacency */
|
|
|
|
srv6_endx_sid_add_single(adj, false,
|
|
|
|
NULL,
|
|
|
|
&sid_addr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
zlog_warn("%s: unsupported behavior %u",
|
|
|
|
__func__, ctx.behavior);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ZAPI_SRV6_SID_RELEASED:
|
|
|
|
sr_debug("SRv6 SID %pI6 %s: RELEASED", &sid_addr,
|
|
|
|
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
|
|
|
|
break;
|
|
|
|
case ZAPI_SRV6_SID_FAIL_ALLOC:
|
|
|
|
sr_debug("SRv6 SID %pI6 %s: Failed to allocate",
|
|
|
|
&sid_addr,
|
|
|
|
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
|
|
|
|
|
|
|
|
/* Error will be logged by zebra module */
|
|
|
|
break;
|
|
|
|
case ZAPI_SRV6_SID_FAIL_RELEASE:
|
|
|
|
zlog_warn("%s: SRv6 SID %pI6 %s failure to release",
|
|
|
|
__func__, &sid_addr,
|
|
|
|
srv6_sid_ctx2str(buf, sizeof(buf), &ctx));
|
|
|
|
|
|
|
|
/* Error will be logged by zebra module */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Regenerate LSPs to advertise the new locator and the SID */
|
|
|
|
lsp_regenerate_schedule(area, area->is_type, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-10-20 13:07:47 +02:00
|
|
|
static zclient_handler *const isis_handlers[] = {
|
|
|
|
[ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra,
|
|
|
|
[ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add,
|
|
|
|
[ZEBRA_INTERFACE_ADDRESS_DELETE] = isis_zebra_if_address_del,
|
|
|
|
[ZEBRA_INTERFACE_LINK_PARAMS] = isis_zebra_link_params,
|
|
|
|
[ZEBRA_REDISTRIBUTE_ROUTE_ADD] = isis_zebra_read,
|
|
|
|
[ZEBRA_REDISTRIBUTE_ROUTE_DEL] = isis_zebra_read,
|
|
|
|
|
|
|
|
[ZEBRA_OPAQUE_MESSAGE] = isis_opaque_msg_handler,
|
|
|
|
|
|
|
|
[ZEBRA_CLIENT_CLOSE_NOTIFY] = isis_zebra_client_close_notify,
|
2023-02-22 11:11:35 +01:00
|
|
|
|
2023-02-09 19:09:04 +01:00
|
|
|
[ZEBRA_SRV6_LOCATOR_ADD] = isis_zebra_process_srv6_locator_add,
|
2023-02-09 19:11:05 +01:00
|
|
|
[ZEBRA_SRV6_LOCATOR_DELETE] = isis_zebra_process_srv6_locator_delete,
|
2024-05-09 11:51:16 +02:00
|
|
|
[ZEBRA_SRV6_SID_NOTIFY] = isis_zebra_srv6_sid_notify,
|
2021-10-20 13:07:47 +02:00
|
|
|
};
|
|
|
|
|
2025-01-23 19:16:11 +01:00
|
|
|
void isis_zebra_init(struct event_loop *mst, int instance)
|
2003-12-23 09:09:43 +01:00
|
|
|
{
|
2019-08-04 03:02:37 +02:00
|
|
|
/* Initialize asynchronous zclient. */
|
2025-01-23 19:16:11 +01:00
|
|
|
isis_zclient = zclient_new(mst, &zclient_options_default, isis_handlers,
|
2021-10-20 13:07:47 +02:00
|
|
|
array_size(isis_handlers));
|
2025-01-23 19:16:11 +01:00
|
|
|
zclient_init(isis_zclient, PROTO_TYPE, 0, &isisd_privs);
|
|
|
|
isis_zclient->zebra_connected = isis_zebra_connected;
|
2017-07-17 14:03:14 +02:00
|
|
|
|
2019-08-04 03:02:37 +02:00
|
|
|
/* Initialize special zclient for synchronous message exchanges. */
|
2025-01-23 19:16:11 +01:00
|
|
|
zclient_sync = zclient_new(mst, &zclient_options_sync, NULL, 0);
|
2019-08-04 03:02:37 +02:00
|
|
|
zclient_sync->sock = -1;
|
|
|
|
zclient_sync->redist_default = ZEBRA_ROUTE_ISIS;
|
|
|
|
zclient_sync->instance = instance;
|
2020-04-10 17:12:48 +02:00
|
|
|
/*
|
|
|
|
* session_id must be different from default value (0) to distinguish
|
|
|
|
* the asynchronous socket from the synchronous one
|
|
|
|
*/
|
|
|
|
zclient_sync->session_id = 1;
|
2019-08-04 03:02:37 +02:00
|
|
|
zclient_sync->privs = &isisd_privs;
|
2003-12-23 09:09:43 +01:00
|
|
|
}
|
2017-06-30 16:31:09 +02:00
|
|
|
|
|
|
|
void isis_zebra_stop(void)
|
|
|
|
{
|
2025-01-23 19:16:11 +01:00
|
|
|
zclient_unregister_opaque(isis_zclient, LDP_RLFA_LABELS);
|
|
|
|
zclient_unregister_opaque(isis_zclient, LDP_IGP_SYNC_IF_STATE_UPDATE);
|
|
|
|
zclient_unregister_opaque(isis_zclient, LDP_IGP_SYNC_ANNOUNCE_UPDATE);
|
2020-06-04 18:03:04 +02:00
|
|
|
zclient_stop(zclient_sync);
|
|
|
|
zclient_free(zclient_sync);
|
2025-01-23 19:16:11 +01:00
|
|
|
zclient_stop(isis_zclient);
|
|
|
|
zclient_free(isis_zclient);
|
2017-06-30 16:31:09 +02:00
|
|
|
}
|