2017-03-09 05:07:46 +01:00
/*
* EIGRP Network Related Functions .
* Copyright ( C ) 2013 - 2014
* Authors :
* Donnie Savage
* Jan Janovic
* Matej Perina
* Peter Orsag
* Peter Paluch
*
* This file is part of GNU Zebra .
*
* GNU Zebra is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 , or ( at your option ) any
* later version .
*
* GNU Zebra is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* General Public License for more details .
*
2017-05-13 10:25:29 +02:00
* You should have received a copy of the GNU General Public License along
* with this program ; see the file COPYING ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
2017-03-09 05:07:46 +01:00
*/
# include <zebra.h>
# include "thread.h"
# include "linklist.h"
# include "prefix.h"
# include "if.h"
# include "sockunion.h"
# include "log.h"
# include "sockopt.h"
# include "privs.h"
# include "table.h"
# include "vty.h"
2018-06-18 16:58:43 +02:00
# include "lib_errors.h"
2017-03-09 05:07:46 +01:00
# include "eigrpd/eigrp_structs.h"
# include "eigrpd/eigrpd.h"
# include "eigrpd/eigrp_interface.h"
# include "eigrpd/eigrp_neighbor.h"
# include "eigrpd/eigrp_packet.h"
# include "eigrpd/eigrp_zebra.h"
# include "eigrpd/eigrp_vty.h"
# include "eigrpd/eigrp_network.h"
2018-09-22 18:43:32 +02:00
static int eigrp_network_match_iface ( const struct prefix * connected_prefix ,
const struct prefix * prefix ) ;
2017-03-09 05:07:46 +01:00
static void eigrp_network_run_interface ( struct eigrp * , struct prefix * ,
struct interface * ) ;
2019-06-15 19:10:05 +02:00
int eigrp_sock_init ( struct vrf * vrf )
2017-03-09 05:07:46 +01:00
{
2019-09-25 02:48:10 +02:00
int eigrp_sock = - 1 ;
2018-06-18 17:12:27 +02:00
int ret ;
# ifdef IP_HDRINCL
int hincl = 1 ;
# endif
2017-07-17 14:03:14 +02:00
2019-09-25 02:48:10 +02:00
if ( ! vrf )
return eigrp_sock ;
2019-08-13 15:47:23 +02:00
frr_with_privs ( & eigrpd_privs ) {
2019-06-15 19:10:05 +02:00
eigrp_sock = vrf_socket (
AF_INET , SOCK_RAW , IPPROTO_EIGRPIGP , vrf - > vrf_id ,
vrf - > vrf_id ! = VRF_DEFAULT ? vrf - > name : NULL ) ;
2018-08-10 18:46:07 +02:00
if ( eigrp_sock < 0 ) {
2022-09-12 09:17:01 +02:00
zlog_err ( " %s: socket: %s " ,
__func__ , safe_strerror ( errno ) ) ;
2018-08-10 18:46:07 +02:00
exit ( 1 ) ;
}
2017-03-09 05:07:46 +01:00
# ifdef IP_HDRINCL
2018-08-10 18:46:07 +02:00
/* we will include IP header with packet */
ret = setsockopt ( eigrp_sock , IPPROTO_IP , IP_HDRINCL , & hincl ,
sizeof ( hincl ) ) ;
if ( ret < 0 ) {
zlog_warn ( " Can't set IP_HDRINCL option for fd %d: %s " ,
eigrp_sock , safe_strerror ( errno ) ) ;
}
2017-03-09 05:07:46 +01:00
# elif defined(IPTOS_PREC_INTERNETCONTROL)
# warning "IP_HDRINCL not available on this system"
# warning "using IPTOS_PREC_INTERNETCONTROL"
2018-08-10 18:46:07 +02:00
ret = setsockopt_ipv4_tos ( eigrp_sock ,
IPTOS_PREC_INTERNETCONTROL ) ;
if ( ret < 0 ) {
zlog_warn ( " can't set sockopt IP_TOS %d to socket %d: %s " ,
tos , eigrp_sock , safe_strerror ( errno ) ) ;
close ( eigrp_sock ) ; /* Prevent sd leak. */
return ret ;
}
2017-03-09 05:07:46 +01:00
# else /* !IPTOS_PREC_INTERNETCONTROL */
# warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
2018-08-10 18:46:07 +02:00
zlog_warn ( " IP_HDRINCL option not available " ) ;
2017-03-09 05:07:46 +01:00
# endif /* IP_HDRINCL */
2018-08-10 18:46:07 +02:00
ret = setsockopt_ifindex ( AF_INET , eigrp_sock , 1 ) ;
if ( ret < 0 )
zlog_warn ( " Can't set pktinfo option for fd %d " ,
eigrp_sock ) ;
2017-03-09 05:07:46 +01:00
}
return eigrp_sock ;
}
void eigrp_adjust_sndbuflen ( struct eigrp * eigrp , unsigned int buflen )
{
int newbuflen ;
/* Check if any work has to be done at all. */
if ( eigrp - > maxsndbuflen > = buflen )
return ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
/* Now we try to set SO_SNDBUF to what our caller has requested
* ( the MTU of a newly added interface ) . However , if the OS has
* truncated the actual buffer size to somewhat less size , try
* to detect it and update our records appropriately . The OS
* may allocate more buffer space , than requested , this isn ' t
* a error .
*/
2019-04-08 18:08:00 +02:00
setsockopt_so_sendbuf ( eigrp - > fd , buflen ) ;
newbuflen = getsockopt_so_sendbuf ( eigrp - > fd ) ;
if ( newbuflen < 0 | | newbuflen < ( int ) buflen )
zlog_warn ( " %s: tried to set SO_SNDBUF to %u, but got %d " ,
__func__ , buflen , newbuflen ) ;
if ( newbuflen > = 0 )
eigrp - > maxsndbuflen = ( unsigned int ) newbuflen ;
else
zlog_warn ( " %s: failed to get SO_SNDBUF " , __func__ ) ;
2017-03-09 05:07:46 +01:00
}
int eigrp_if_ipmulticast ( struct eigrp * top , struct prefix * p ,
unsigned int ifindex )
{
2018-03-27 21:13:34 +02:00
uint8_t val ;
2017-03-09 05:07:46 +01:00
int ret , len ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
val = 0 ;
len = sizeof ( val ) ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
/* Prevent receiving self-origined multicast packets. */
ret = setsockopt ( top - > fd , IPPROTO_IP , IP_MULTICAST_LOOP , ( void * ) & val ,
len ) ;
if ( ret < 0 )
zlog_warn (
" can't setsockopt IP_MULTICAST_LOOP (0) for fd %d: %s " ,
top - > fd , safe_strerror ( errno ) ) ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
/* Explicitly set multicast ttl to 1 -- endo. */
val = 1 ;
ret = setsockopt ( top - > fd , IPPROTO_IP , IP_MULTICAST_TTL , ( void * ) & val ,
len ) ;
if ( ret < 0 )
zlog_warn ( " can't setsockopt IP_MULTICAST_TTL (1) for fd %d: %s " ,
2017-04-08 20:44:58 +02:00
top - > fd , safe_strerror ( errno ) ) ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
ret = setsockopt_ipv4_multicast_if ( top - > fd , p - > u . prefix4 , ifindex ) ;
if ( ret < 0 )
zlog_warn (
2020-10-22 00:55:09 +02:00
" can't setsockopt IP_MULTICAST_IF (fd %d, addr %pI4, ifindex %u): %s " ,
top - > fd , & p - > u . prefix4 , ifindex , safe_strerror ( errno ) ) ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
return ret ;
}
/* Join to the EIGRP multicast group. */
int eigrp_if_add_allspfrouters ( struct eigrp * top , struct prefix * p ,
2017-04-08 20:44:58 +02:00
unsigned int ifindex )
2017-03-09 05:07:46 +01:00
{
int ret ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
ret = setsockopt_ipv4_multicast (
top - > fd , IP_ADD_MEMBERSHIP , p - > u . prefix4 ,
htonl ( EIGRP_MULTICAST_ADDRESS ) , ifindex ) ;
if ( ret < 0 )
zlog_warn (
2020-10-22 00:55:09 +02:00
" can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s; perhaps a kernel limit on # of multicast group memberships has been exceeded? " ,
top - > fd , & p - > u . prefix4 , ifindex , safe_strerror ( errno ) ) ;
2017-03-09 05:07:46 +01:00
else
2020-10-22 00:55:09 +02:00
zlog_debug ( " interface %pI4 [%u] join EIGRP Multicast group. " ,
& p - > u . prefix4 , ifindex ) ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
return ret ;
}
int eigrp_if_drop_allspfrouters ( struct eigrp * top , struct prefix * p ,
2017-04-08 20:44:58 +02:00
unsigned int ifindex )
2017-03-09 05:07:46 +01:00
{
int ret ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
ret = setsockopt_ipv4_multicast (
top - > fd , IP_DROP_MEMBERSHIP , p - > u . prefix4 ,
htonl ( EIGRP_MULTICAST_ADDRESS ) , ifindex ) ;
if ( ret < 0 )
zlog_warn (
2020-10-22 00:55:09 +02:00
" can't setsockopt IP_DROP_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllSPFRouters): %s " ,
top - > fd , & p - > u . prefix4 , ifindex , safe_strerror ( errno ) ) ;
2017-03-09 05:07:46 +01:00
else
2020-10-22 00:55:09 +02:00
zlog_debug ( " interface %pI4 [%u] leave EIGRP Multicast group. " ,
& p - > u . prefix4 , ifindex ) ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
return ret ;
}
2017-08-23 21:35:27 +02:00
int eigrp_network_set ( struct eigrp * eigrp , struct prefix * p )
2017-03-09 05:07:46 +01:00
{
2019-06-15 21:21:39 +02:00
struct vrf * vrf = vrf_lookup_by_id ( eigrp - > vrf_id ) ;
2017-03-09 05:07:46 +01:00
struct route_node * rn ;
struct interface * ifp ;
2017-07-17 14:03:14 +02:00
2020-04-08 07:57:15 +02:00
rn = route_node_get ( eigrp - > networks , p ) ;
2017-03-09 05:07:46 +01:00
if ( rn - > info ) {
/* There is already same network statement. */
route_unlock_node ( rn ) ;
return 0 ;
}
2017-07-17 14:03:14 +02:00
2017-08-23 21:39:30 +02:00
struct prefix * pref = prefix_new ( ) ;
2021-06-02 19:03:52 +02:00
prefix_copy ( pref , p ) ;
2017-03-09 05:07:46 +01:00
rn - > info = ( void * ) pref ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
/* Schedule Router ID Update. */
2020-02-06 07:49:02 +01:00
if ( eigrp - > router_id . s_addr = = INADDR_ANY )
2017-07-14 00:45:20 +02:00
eigrp_router_id_update ( eigrp ) ;
2017-03-09 05:07:46 +01:00
/* Run network config now. */
/* Get target interface. */
2017-10-06 20:25:58 +02:00
FOR_ALL_INTERFACES ( vrf , ifp ) {
2017-03-09 05:07:46 +01:00
zlog_debug ( " Setting up %s " , ifp - > name ) ;
2017-08-23 21:39:30 +02:00
eigrp_network_run_interface ( eigrp , p , ifp ) ;
2017-03-09 05:07:46 +01:00
}
return 1 ;
}
/* Check whether interface matches given network
* returns : 1 , true . 0 , false
*/
2018-09-22 18:43:32 +02:00
static int eigrp_network_match_iface ( const struct prefix * co_prefix ,
2017-03-09 05:07:46 +01:00
const struct prefix * net )
{
/* new approach: more elegant and conceptually clean */
2018-09-22 18:43:32 +02:00
return prefix_match_network_statement ( net , co_prefix ) ;
2017-03-09 05:07:46 +01:00
}
static void eigrp_network_run_interface ( struct eigrp * eigrp , struct prefix * p ,
2017-04-08 20:44:58 +02:00
struct interface * ifp )
2017-03-09 05:07:46 +01:00
{
2017-10-03 01:50:39 +02:00
struct eigrp_interface * ei ;
2017-03-09 05:07:46 +01:00
struct listnode * cnode ;
struct connected * co ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
/* if interface prefix is match specified prefix,
2017-04-08 20:44:58 +02:00
then create socket and join multicast group . */
2017-03-09 05:07:46 +01:00
for ( ALL_LIST_ELEMENTS_RO ( ifp - > connected , cnode , co ) ) {
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
if ( CHECK_FLAG ( co - > flags , ZEBRA_IFA_SECONDARY ) )
continue ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
if ( p - > family = = co - > address - > family & & ! ifp - > info
2018-09-22 18:43:32 +02:00
& & eigrp_network_match_iface ( co - > address , p ) ) {
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
ei = eigrp_if_new ( eigrp , ifp , co - > address ) ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
/* Relate eigrp interface to eigrp instance. */
ei - > eigrp = eigrp ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
/* if router_id is not configured, dont bring up
* interfaces .
* eigrp_router_id_update ( ) will call eigrp_if_update
* whenever r - id is configured instead .
*/
if ( if_is_operative ( ifp ) )
eigrp_if_up ( ei ) ;
}
}
}
void eigrp_if_update ( struct interface * ifp )
{
struct listnode * node , * nnode ;
struct route_node * rn ;
2019-09-04 01:22:27 +02:00
struct eigrp * eigrp ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
/*
* In the event there are multiple eigrp autonymnous systems running ,
* we need to check eac one and add the interface as approperate
*/
for ( ALL_LIST_ELEMENTS ( eigrp_om - > eigrp , node , nnode , eigrp ) ) {
2021-10-22 00:17:40 +02:00
if ( ifp - > vrf - > vrf_id ! = eigrp - > vrf_id )
2019-06-16 00:25:58 +02:00
continue ;
2017-03-09 05:07:46 +01:00
/* EIGRP must be on and Router-ID must be configured. */
2020-12-14 20:01:31 +01:00
if ( eigrp - > router_id . s_addr = = INADDR_ANY )
2017-03-09 05:07:46 +01:00
continue ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
/* Run each network for this interface. */
for ( rn = route_top ( eigrp - > networks ) ; rn ; rn = route_next ( rn ) )
if ( rn - > info ! = NULL ) {
eigrp_network_run_interface ( eigrp , & rn - > p , ifp ) ;
}
}
}
2017-08-23 21:35:27 +02:00
int eigrp_network_unset ( struct eigrp * eigrp , struct prefix * p )
2017-03-09 05:07:46 +01:00
{
struct route_node * rn ;
struct listnode * node , * nnode ;
struct eigrp_interface * ei ;
struct prefix * pref ;
2017-07-17 14:03:14 +02:00
2017-08-23 21:35:27 +02:00
rn = route_node_lookup ( eigrp - > networks , p ) ;
2017-03-09 05:07:46 +01:00
if ( rn = = NULL )
return 0 ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
pref = rn - > info ;
route_unlock_node ( rn ) ;
2017-07-17 14:03:14 +02:00
2017-08-23 21:35:27 +02:00
if ( ! IPV4_ADDR_SAME ( & pref - > u . prefix4 , & p - > u . prefix4 ) )
2017-04-08 20:44:58 +02:00
return 0 ;
2017-07-17 14:03:14 +02:00
2019-10-30 01:05:27 +01:00
prefix_ipv4_free ( ( struct prefix_ipv4 * * ) & rn - > info ) ;
2017-03-09 05:07:46 +01:00
route_unlock_node ( rn ) ; /* initial reference */
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
/* Find interfaces that not configured already. */
for ( ALL_LIST_ELEMENTS ( eigrp - > eiflist , node , nnode , ei ) ) {
2018-09-22 18:43:32 +02:00
bool found = false ;
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
for ( rn = route_top ( eigrp - > networks ) ; rn ; rn = route_next ( rn ) ) {
if ( rn - > info = = NULL )
continue ;
2017-07-17 14:03:14 +02:00
2019-02-11 13:16:35 +01:00
if ( eigrp_network_match_iface ( & ei - > address , & rn - > p ) ) {
2018-09-22 18:43:32 +02:00
found = true ;
2017-03-09 05:07:46 +01:00
route_unlock_node ( rn ) ;
break ;
}
}
2017-07-17 14:03:14 +02:00
2018-09-22 18:43:32 +02:00
if ( ! found ) {
2017-03-09 05:07:46 +01:00
eigrp_if_free ( ei , INTERFACE_DOWN_BY_VTY ) ;
}
}
2017-07-17 14:03:14 +02:00
2017-03-09 05:07:46 +01:00
return 1 ;
}
void eigrp_external_routes_refresh ( struct eigrp * eigrp , int type )
{
}