2000-03-20 21:50:17 +00:00
/*
* BIRD - - BGP Packet Processing
*
* ( c ) 2000 Martin Mares < mj @ ucw . cz >
2016-12-07 13:11:28 +00:00
* ( c ) 2008 - - 2016 Ondrej Zajicek < santiago @ crfreenet . org >
* ( c ) 2008 - - 2016 CZ . NIC z . s . p . o .
2000-03-20 21:50:17 +00:00
*
* Can be freely distributed and used under the terms of the GNU GPL .
*/
2000-05-02 16:07:41 +00:00
# undef LOCAL_DEBUG
2000-03-21 15:53:50 +00:00
2016-12-07 13:11:28 +00:00
# include <stdlib.h>
2000-03-20 21:50:17 +00:00
# include "nest/bird.h"
# include "nest/iface.h"
# include "nest/protocol.h"
# include "nest/route.h"
2008-10-26 21:36:08 +00:00
# include "nest/attrs.h"
2018-11-20 16:38:19 +00:00
# include "proto/mrt/mrt.h"
2000-03-20 21:50:17 +00:00
# include "conf/conf.h"
2000-03-21 15:53:50 +00:00
# include "lib/unaligned.h"
2016-12-07 17:28:07 +00:00
# include "lib/flowspec.h"
2000-03-21 15:53:50 +00:00
# include "lib/socket.h"
2000-03-20 21:50:17 +00:00
2008-12-19 00:34:39 +00:00
# include "nest/cli.h"
2000-03-20 21:50:17 +00:00
# include "bgp.h"
2021-03-29 20:45:21 +00:00
# include "proto/bmp/bmp.h"
2000-03-21 15:53:50 +00:00
2015-03-29 16:27:13 +00:00
# define BGP_RR_REQUEST 0
# define BGP_RR_BEGIN 1
# define BGP_RR_END 2
2017-03-22 14:00:07 +00:00
# define BGP_NLRI_MAX (4 + 1 + 32)
# define BGP_MPLS_BOS 1 /* Bottom-of-stack bit */
# define BGP_MPLS_MAX 10 /* Max number of labels that 24*n <= 255 */
# define BGP_MPLS_NULL 3 /* Implicit NULL label */
# define BGP_MPLS_MAGIC 0x800000 /* Magic withdraw label value, RFC 3107 3 */
2015-03-29 16:27:13 +00:00
2014-10-02 09:41:34 +00:00
static struct tbf rl_rcv_update = TBF_DEFAULT_LOG_LIMITS ;
static struct tbf rl_snd_update = TBF_DEFAULT_LOG_LIMITS ;
2009-02-26 13:23:54 +00:00
2013-07-25 11:55:24 +00:00
/* Table for state -> RFC 6608 FSM error subcodes */
static byte fsm_err_subcode [ BS_MAX ] = {
[ BS_OPENSENT ] = 1 ,
[ BS_OPENCONFIRM ] = 2 ,
[ BS_ESTABLISHED ] = 3
} ;
2016-12-07 13:11:28 +00:00
static struct bgp_channel *
bgp_get_channel ( struct bgp_proto * p , u32 afi )
{
uint i ;
for ( i = 0 ; i < p - > channel_count ; i + + )
if ( p - > afi_map [ i ] = = afi )
return p - > channel_map [ i ] ;
return NULL ;
}
static inline void
put_af3 ( byte * buf , u32 id )
{
put_u16 ( buf , id > > 16 ) ;
buf [ 2 ] = id & 0xff ;
}
static inline void
put_af4 ( byte * buf , u32 id )
{
put_u16 ( buf , id > > 16 ) ;
buf [ 2 ] = 0 ;
buf [ 3 ] = id & 0xff ;
}
static inline u32
get_af3 ( byte * buf )
{
return ( get_u16 ( buf ) < < 16 ) | buf [ 2 ] ;
}
static inline u32
get_af4 ( byte * buf )
{
return ( get_u16 ( buf ) < < 16 ) | buf [ 3 ] ;
}
2018-11-20 16:38:19 +00:00
static void
init_mrt_bgp_data ( struct bgp_conn * conn , struct mrt_bgp_data * d )
2010-01-03 11:17:52 +00:00
{
struct bgp_proto * p = conn - > bgp ;
2018-11-20 16:38:19 +00:00
int p_ok = conn - > state > = BS_OPENCONFIRM ;
2010-01-03 11:17:52 +00:00
2018-11-20 16:38:19 +00:00
memset ( d , 0 , sizeof ( struct mrt_bgp_data ) ) ;
d - > peer_as = p - > remote_as ;
d - > local_as = p - > local_as ;
d - > index = ( p - > neigh & & p - > neigh - > iface ) ? p - > neigh - > iface - > index : 0 ;
2019-04-02 15:22:31 +00:00
d - > af = ipa_is_ip4 ( p - > remote_ip ) ? BGP_AFI_IPV4 : BGP_AFI_IPV6 ;
2018-11-20 16:38:19 +00:00
d - > peer_ip = conn - > sk ? conn - > sk - > daddr : IPA_NONE ;
d - > local_ip = conn - > sk ? conn - > sk - > saddr : IPA_NONE ;
d - > as4 = p_ok ? p - > as4_session : 0 ;
}
2010-01-03 11:17:52 +00:00
2018-11-20 16:38:19 +00:00
static uint bgp_find_update_afi ( byte * pos , uint len ) ;
2016-12-07 13:11:28 +00:00
2018-11-20 16:38:19 +00:00
static int
bgp_estimate_add_path ( struct bgp_proto * p , byte * pkt , uint len )
{
/* No need to estimate it for other messages than UPDATE */
if ( pkt [ 18 ] ! = PKT_UPDATE )
return 0 ;
/* 1 -> no channel, 2 -> all channels, 3 -> some channels */
if ( p - > summary_add_path_rx < 3 )
return p - > summary_add_path_rx = = 2 ;
uint afi = bgp_find_update_afi ( pkt , len ) ;
struct bgp_channel * c = bgp_get_channel ( p , afi ) ;
if ( ! c )
2016-12-07 13:11:28 +00:00
{
2018-11-20 16:38:19 +00:00
/* Either frame error (if !afi) or unknown AFI/SAFI,
will be reported later in regular parsing */
BGP_TRACE ( D_PACKETS , " MRT processing noticed invalid packet " ) ;
return 0 ;
2016-12-07 13:11:28 +00:00
}
2010-01-03 11:17:52 +00:00
2018-11-20 16:38:19 +00:00
return c - > add_path_rx ;
2010-01-03 11:17:52 +00:00
}
static void
2018-11-20 16:38:19 +00:00
bgp_dump_message ( struct bgp_conn * conn , byte * pkt , uint len )
2010-01-03 11:17:52 +00:00
{
2018-11-20 16:38:19 +00:00
struct mrt_bgp_data d ;
init_mrt_bgp_data ( conn , & d ) ;
2010-01-03 11:17:52 +00:00
2018-11-20 16:38:19 +00:00
d . message = pkt ;
d . msg_len = len ;
d . add_path = bgp_estimate_add_path ( conn - > bgp , pkt , len ) ;
2010-01-03 11:17:52 +00:00
2018-11-20 16:38:19 +00:00
mrt_dump_bgp_message ( & d ) ;
2010-01-03 11:17:52 +00:00
}
void
2018-11-20 16:38:19 +00:00
bgp_dump_state_change ( struct bgp_conn * conn , uint old , uint new )
2010-01-03 11:17:52 +00:00
{
2018-11-20 16:38:19 +00:00
struct mrt_bgp_data d ;
init_mrt_bgp_data ( conn , & d ) ;
d . old_state = old ;
d . new_state = new ;
2010-01-03 11:17:52 +00:00
2018-11-20 16:38:19 +00:00
mrt_dump_bgp_state_change ( & d ) ;
2010-01-03 11:17:52 +00:00
}
2000-03-21 15:53:50 +00:00
static byte *
bgp_create_notification ( struct bgp_conn * conn , byte * buf )
{
2000-05-02 16:07:41 +00:00
struct bgp_proto * p = conn - > bgp ;
BGP_TRACE ( D_PACKETS , " Sending NOTIFICATION(code=%d.%d) " , conn - > notify_code , conn - > notify_subcode ) ;
2000-03-21 15:53:50 +00:00
buf [ 0 ] = conn - > notify_code ;
buf [ 1 ] = conn - > notify_subcode ;
2000-04-25 21:13:25 +00:00
memcpy ( buf + 2 , conn - > notify_data , conn - > notify_size ) ;
return buf + 2 + conn - > notify_size ;
2000-03-21 15:53:50 +00:00
}
2009-03-05 10:52:47 +00:00
2016-12-07 13:11:28 +00:00
/* Capability negotiation as per RFC 5492 */
2009-03-05 10:52:47 +00:00
2016-12-07 13:11:28 +00:00
const struct bgp_af_caps *
bgp_find_af_caps ( struct bgp_caps * caps , u32 afi )
2009-11-26 19:47:59 +00:00
{
2016-12-07 13:11:28 +00:00
struct bgp_af_caps * ac ;
2009-11-26 19:47:59 +00:00
2016-12-07 13:11:28 +00:00
WALK_AF_CAPS ( caps , ac )
if ( ac - > afi = = afi )
return ac ;
return NULL ;
2015-11-25 14:52:58 +00:00
}
2016-12-07 13:11:28 +00:00
static struct bgp_af_caps *
2019-08-21 15:16:08 +00:00
bgp_get_af_caps ( struct bgp_caps * * pcaps , u32 afi )
2014-03-20 13:07:12 +00:00
{
2019-08-21 15:16:08 +00:00
struct bgp_caps * caps = * pcaps ;
2016-12-07 13:11:28 +00:00
struct bgp_af_caps * ac ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
WALK_AF_CAPS ( caps , ac )
if ( ac - > afi = = afi )
return ac ;
2014-03-20 13:07:12 +00:00
2019-08-21 15:16:08 +00:00
uint n = caps - > af_count ;
if ( uint_is_pow2 ( n ) )
* pcaps = caps = mb_realloc ( caps , sizeof ( struct bgp_caps ) +
( 2 * n ) * sizeof ( struct bgp_af_caps ) ) ;
2016-12-07 13:11:28 +00:00
ac = & caps - > af_data [ caps - > af_count + + ] ;
memset ( ac , 0 , sizeof ( struct bgp_af_caps ) ) ;
ac - > afi = afi ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
return ac ;
2014-03-20 13:07:12 +00:00
}
2016-12-07 13:11:28 +00:00
static int
bgp_af_caps_cmp ( const void * X , const void * Y )
2014-03-20 13:07:12 +00:00
{
2016-12-07 13:11:28 +00:00
const struct bgp_af_caps * x = X , * y = Y ;
return ( x - > afi < y - > afi ) ? - 1 : ( x - > afi > y - > afi ) ? 1 : 0 ;
2014-03-20 13:07:12 +00:00
}
2023-05-18 23:02:57 +00:00
struct bgp_caps *
bgp_alloc_capabilities ( struct bgp_proto * p , int n )
{
struct bgp_caps * caps = mb_allocz ( p - > p . pool , sizeof ( struct bgp_caps ) + n * sizeof ( struct bgp_af_caps ) ) ;
caps - > role = BGP_ROLE_UNDEFINED ;
return caps ;
}
2008-10-26 21:36:08 +00:00
2019-04-08 14:39:22 +00:00
void
bgp_prepare_capabilities ( struct bgp_conn * conn )
2012-08-14 14:25:22 +00:00
{
2016-12-07 13:11:28 +00:00
struct bgp_proto * p = conn - > bgp ;
struct bgp_channel * c ;
struct bgp_caps * caps ;
struct bgp_af_caps * ac ;
2012-08-14 14:25:22 +00:00
2019-04-08 14:39:22 +00:00
if ( ! p - > cf - > capabilities )
{
/* Just prepare empty local_caps */
2023-05-18 23:02:57 +00:00
conn - > local_caps = bgp_alloc_capabilities ( p , 0 ) ;
2019-04-08 14:39:22 +00:00
return ;
}
2012-08-14 14:25:22 +00:00
2019-04-08 14:39:22 +00:00
/* Prepare bgp_caps structure */
2016-12-07 13:11:28 +00:00
int n = list_length ( & p - > p . channels ) ;
2023-05-18 23:02:57 +00:00
caps = bgp_alloc_capabilities ( p , n ) ;
2016-12-07 13:11:28 +00:00
conn - > local_caps = caps ;
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
caps - > as4_support = p - > cf - > enable_as4 ;
caps - > ext_messages = p - > cf - > enable_extended_messages ;
caps - > route_refresh = p - > cf - > enable_refresh ;
2023-09-27 10:51:55 +00:00
caps - > enhanced_refresh = p - > cf - > enable_refresh & & p - > cf - > enable_enhanced_refresh ;
2022-07-11 15:19:34 +00:00
caps - > role = p - > cf - > local_role ;
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
if ( caps - > as4_support )
caps - > as4_number = p - > public_as ;
2015-03-29 16:27:13 +00:00
2016-12-07 13:11:28 +00:00
if ( p - > cf - > gr_mode )
{
caps - > gr_aware = 1 ;
caps - > gr_time = p - > cf - > gr_time ;
caps - > gr_flags = p - > p . gr_recovery ? BGP_GRF_RESTART : 0 ;
}
2015-03-29 16:27:13 +00:00
2018-07-31 16:40:38 +00:00
if ( p - > cf - > llgr_mode )
caps - > llgr_aware = 1 ;
2021-02-10 15:53:57 +00:00
if ( p - > cf - > enable_hostname & & config - > hostname )
{
size_t length = strlen ( config - > hostname ) ;
char * hostname = mb_allocz ( p - > p . pool , length + 1 ) ;
memcpy ( hostname , config - > hostname , length + 1 ) ;
caps - > hostname = hostname ;
}
2016-12-07 13:11:28 +00:00
/* Allocate and fill per-AF fields */
2022-09-08 17:41:02 +00:00
BGP_WALK_CHANNELS ( p , c )
2016-12-07 13:11:28 +00:00
{
ac = & caps - > af_data [ caps - > af_count + + ] ;
ac - > afi = c - > afi ;
ac - > ready = 1 ;
2000-05-02 16:07:41 +00:00
2017-01-24 01:00:35 +00:00
ac - > ext_next_hop = bgp_channel_is_ipv4 ( c ) & & c - > cf - > ext_next_hop ;
2019-04-08 14:39:22 +00:00
caps - > any_ext_next_hop | = ac - > ext_next_hop ;
2017-01-24 01:00:35 +00:00
2016-12-07 13:11:28 +00:00
ac - > add_path = c - > cf - > add_path ;
2019-04-08 14:39:22 +00:00
caps - > any_add_path | = ac - > add_path ;
2008-12-24 16:24:41 +00:00
2016-12-07 13:11:28 +00:00
if ( c - > cf - > gr_able )
2008-12-24 16:24:41 +00:00
{
2016-12-07 13:11:28 +00:00
ac - > gr_able = 1 ;
if ( p - > p . gr_recovery )
ac - > gr_af_flags | = BGP_GRF_FORWARDING ;
2008-12-24 16:24:41 +00:00
}
2018-07-31 16:40:38 +00:00
if ( c - > cf - > llgr_able )
{
ac - > llgr_able = 1 ;
ac - > llgr_time = c - > cf - > llgr_time ;
if ( p - > p . gr_recovery )
ac - > llgr_flags | = BGP_LLGRF_FORWARDING ;
}
2016-12-07 13:11:28 +00:00
}
2008-12-24 16:24:41 +00:00
2016-12-07 13:11:28 +00:00
/* Sort capability fields by AFI/SAFI */
qsort ( caps - > af_data , caps - > af_count , sizeof ( struct bgp_af_caps ) , bgp_af_caps_cmp ) ;
2019-04-08 14:39:22 +00:00
}
2008-10-26 21:36:08 +00:00
2019-04-08 14:39:22 +00:00
static byte *
bgp_write_capabilities ( struct bgp_conn * conn , byte * buf )
{
struct bgp_proto * p = conn - > bgp ;
struct bgp_caps * caps = conn - > local_caps ;
struct bgp_af_caps * ac ;
byte * buf_head = buf ;
byte * data ;
2009-03-05 10:52:47 +00:00
2016-12-07 13:11:28 +00:00
/* Create capability list in buffer */
2009-03-13 11:49:44 +00:00
2016-12-23 22:03:26 +00:00
/*
2018-07-31 16:40:38 +00:00
* Note that max length is ~ 22 + 21 * af_count . With max 12 channels that is
2019-08-20 17:12:59 +00:00
* 274. We are limited just by buffer size ( 4096 , minus header ) , as we support
* extended optional parameres . Therefore , we have enough space for expansion .
2016-12-23 22:03:26 +00:00
*/
2016-12-07 13:11:28 +00:00
WALK_AF_CAPS ( caps , ac )
if ( ac - > ready )
{
* buf + + = 1 ; /* Capability 1: Multiprotocol extensions */
* buf + + = 4 ; /* Capability data length */
put_af4 ( buf , ac - > afi ) ;
buf + = 4 ;
}
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
if ( caps - > route_refresh )
{
* buf + + = 2 ; /* Capability 2: Support for route refresh */
* buf + + = 0 ; /* Capability data length */
}
2009-11-26 19:47:59 +00:00
2019-04-08 14:39:22 +00:00
if ( caps - > any_ext_next_hop )
2017-01-24 01:00:35 +00:00
{
* buf + + = 5 ; /* Capability 5: Support for extended next hop */
* buf + + = 0 ; /* Capability data length, will be fixed later */
data = buf ;
WALK_AF_CAPS ( caps , ac )
if ( ac - > ext_next_hop )
{
put_af4 ( buf , ac - > afi ) ;
put_u16 ( buf + 4 , BGP_AFI_IPV6 ) ;
buf + = 6 ;
}
data [ - 1 ] = buf - data ;
}
2016-12-07 13:11:28 +00:00
if ( caps - > ext_messages )
{
* buf + + = 6 ; /* Capability 6: Support for extended messages */
* buf + + = 0 ; /* Capability data length */
}
2008-10-26 21:36:08 +00:00
2022-07-11 15:19:34 +00:00
if ( caps - > role ! = BGP_ROLE_UNDEFINED )
{
* buf + + = 9 ; /* Capability 9: Announce chosen BGP role */
* buf + + = 1 ; /* Capability data length */
* buf + + = caps - > role ;
}
2016-12-07 13:11:28 +00:00
if ( caps - > gr_aware )
{
* buf + + = 64 ; /* Capability 64: Support for graceful restart */
* buf + + = 0 ; /* Capability data length, will be fixed later */
data = buf ;
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
put_u16 ( buf , caps - > gr_time ) ;
buf [ 0 ] | = caps - > gr_flags ;
buf + = 2 ;
2015-03-29 16:27:13 +00:00
2016-12-07 13:11:28 +00:00
WALK_AF_CAPS ( caps , ac )
if ( ac - > gr_able )
{
put_af3 ( buf , ac - > afi ) ;
buf [ 3 ] = ac - > gr_af_flags ;
buf + = 4 ;
}
2015-07-18 11:38:21 +00:00
2016-12-07 13:11:28 +00:00
data [ - 1 ] = buf - data ;
}
2000-03-21 15:53:50 +00:00
2016-12-07 13:11:28 +00:00
if ( caps - > as4_support )
{
* buf + + = 65 ; /* Capability 65: Support for 4-octet AS number */
* buf + + = 4 ; /* Capability data length */
put_u32 ( buf , p - > public_as ) ;
buf + = 4 ;
}
2000-04-17 09:37:31 +00:00
2019-04-08 14:39:22 +00:00
if ( caps - > any_add_path )
2016-12-07 13:11:28 +00:00
{
* buf + + = 69 ; /* Capability 69: Support for ADD-PATH */
* buf + + = 0 ; /* Capability data length, will be fixed later */
data = buf ;
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
WALK_AF_CAPS ( caps , ac )
if ( ac - > add_path )
{
put_af3 ( buf , ac - > afi ) ;
buf [ 3 ] = ac - > add_path ;
buf + = 4 ;
}
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
data [ - 1 ] = buf - data ;
}
if ( caps - > enhanced_refresh )
{
* buf + + = 70 ; /* Capability 70: Support for enhanced route refresh */
* buf + + = 0 ; /* Capability data length */
}
2018-07-31 16:40:38 +00:00
if ( caps - > llgr_aware )
{
* buf + + = 71 ; /* Capability 71: Support for long-lived graceful restart */
* buf + + = 0 ; /* Capability data length, will be fixed later */
data = buf ;
WALK_AF_CAPS ( caps , ac )
if ( ac - > llgr_able )
{
put_af3 ( buf , ac - > afi ) ;
buf [ 3 ] = ac - > llgr_flags ;
put_u24 ( buf + 4 , ac - > llgr_time ) ;
buf + = 7 ;
}
data [ - 1 ] = buf - data ;
}
2021-02-10 15:53:57 +00:00
if ( caps - > hostname )
{
* buf + + = 73 ; /* Capability 73: Hostname */
* buf + + = 0 ; /* Capability data length */
data = buf ;
/* Hostname */
size_t length = strlen ( caps - > hostname ) ;
* buf + + = length ;
memcpy ( buf , caps - > hostname , length ) ;
buf + = length ;
/* Domain, not implemented */
* buf + + = 0 ;
data [ - 1 ] = buf - data ;
}
2019-03-15 19:54:01 +00:00
caps - > length = buf - buf_head ;
2016-12-07 13:11:28 +00:00
return buf ;
2000-04-17 09:37:31 +00:00
}
2019-08-20 17:12:59 +00:00
static int
2019-08-21 15:16:08 +00:00
bgp_read_capabilities ( struct bgp_conn * conn , byte * pos , int len )
2009-02-27 14:24:46 +00:00
{
2016-12-07 13:11:28 +00:00
struct bgp_proto * p = conn - > bgp ;
2019-08-21 15:16:08 +00:00
struct bgp_caps * caps ;
2016-12-07 13:11:28 +00:00
struct bgp_af_caps * ac ;
2022-07-11 15:19:34 +00:00
uint err_subcode = 0 ;
2016-12-07 13:11:28 +00:00
int i , cl ;
u32 af ;
2009-02-27 14:24:46 +00:00
2019-08-21 15:16:08 +00:00
if ( ! conn - > remote_caps )
2023-05-18 23:02:57 +00:00
caps = bgp_alloc_capabilities ( p , 1 ) ;
2019-08-21 15:16:08 +00:00
else
{
caps = conn - > remote_caps ;
conn - > remote_caps = NULL ;
}
2019-03-15 19:54:01 +00:00
caps - > length + = len ;
2016-12-07 13:11:28 +00:00
while ( len > 0 )
{
if ( len < 2 | | len < ( 2 + pos [ 1 ] ) )
goto err ;
2000-05-04 09:03:31 +00:00
2016-12-07 13:11:28 +00:00
/* Capability length */
cl = pos [ 1 ] ;
2000-03-30 10:44:20 +00:00
2016-12-07 13:11:28 +00:00
/* Capability type */
switch ( pos [ 0 ] )
2000-04-17 09:37:31 +00:00
{
2016-12-07 13:11:28 +00:00
case 1 : /* Multiprotocol capability, RFC 4760 */
if ( cl ! = 4 )
goto err ;
af = get_af4 ( pos + 2 ) ;
2019-08-21 15:16:08 +00:00
ac = bgp_get_af_caps ( & caps , af ) ;
2016-12-07 13:11:28 +00:00
ac - > ready = 1 ;
break ;
case 2 : /* Route refresh capability, RFC 2918 */
if ( cl ! = 0 )
goto err ;
caps - > route_refresh = 1 ;
break ;
2023-08-22 12:20:59 +00:00
case 5 : /* Extended next hop encoding capability, RFC 8950 */
2017-01-24 01:00:35 +00:00
if ( cl % 6 )
goto err ;
for ( i = 0 ; i < cl ; i + = 6 )
{
/* Specified only for IPv4 prefixes with IPv6 next hops */
if ( ( get_u16 ( pos + 2 + i + 0 ) ! = BGP_AFI_IPV4 ) | |
( get_u16 ( pos + 2 + i + 4 ) ! = BGP_AFI_IPV6 ) )
continue ;
af = get_af4 ( pos + 2 + i ) ;
2019-08-21 15:16:08 +00:00
ac = bgp_get_af_caps ( & caps , af ) ;
2017-01-24 01:00:35 +00:00
ac - > ext_next_hop = 1 ;
}
break ;
2023-02-19 14:35:07 +00:00
case 6 : /* Extended message length capability, RFC 8654 */
2016-12-07 13:11:28 +00:00
if ( cl ! = 0 )
goto err ;
caps - > ext_messages = 1 ;
break ;
2022-07-11 15:19:34 +00:00
case 9 : /* BGP role capability, RFC 9234 */
if ( cl ! = 1 )
goto err ;
/* Reserved value */
if ( pos [ 2 ] = = BGP_ROLE_UNDEFINED )
{ err_subcode = 11 ; goto err ; }
/* Multiple inconsistent values */
if ( ( caps - > role ! = BGP_ROLE_UNDEFINED ) & & ( caps - > role ! = pos [ 2 ] ) )
{ err_subcode = 11 ; goto err ; }
caps - > role = pos [ 2 ] ;
break ;
2016-12-07 13:11:28 +00:00
case 64 : /* Graceful restart capability, RFC 4724 */
if ( cl % 4 ! = 2 )
goto err ;
/* Only the last instance is valid */
WALK_AF_CAPS ( caps , ac )
{
ac - > gr_able = 0 ;
ac - > gr_af_flags = 0 ;
}
caps - > gr_aware = 1 ;
caps - > gr_flags = pos [ 2 ] & 0xf0 ;
caps - > gr_time = get_u16 ( pos + 2 ) & 0x0fff ;
for ( i = 2 ; i < cl ; i + = 4 )
{
af = get_af3 ( pos + 2 + i ) ;
2019-08-21 15:16:08 +00:00
ac = bgp_get_af_caps ( & caps , af ) ;
2016-12-07 13:11:28 +00:00
ac - > gr_able = 1 ;
ac - > gr_af_flags = pos [ 2 + i + 3 ] ;
}
break ;
2017-03-29 11:48:23 +00:00
case 65 : /* AS4 capability, RFC 6793 */
2016-12-07 13:11:28 +00:00
if ( cl ! = 4 )
goto err ;
caps - > as4_support = 1 ;
caps - > as4_number = get_u32 ( pos + 2 ) ;
break ;
case 69 : /* ADD-PATH capability, RFC 7911 */
if ( cl % 4 )
goto err ;
for ( i = 0 ; i < cl ; i + = 4 )
{
byte val = pos [ 2 + i + 3 ] ;
if ( ! val | | ( val > BGP_ADD_PATH_FULL ) )
2000-04-17 09:37:31 +00:00
{
2016-12-07 13:11:28 +00:00
log ( L_WARN " %s: Got ADD-PATH capability with unknown value %u, ignoring " ,
p - > p . name , val ) ;
2000-04-17 09:37:31 +00:00
break ;
}
2016-12-07 13:11:28 +00:00
}
2000-03-21 15:53:50 +00:00
2016-12-07 13:11:28 +00:00
for ( i = 0 ; i < cl ; i + = 4 )
{
af = get_af3 ( pos + 2 + i ) ;
2019-08-21 15:16:08 +00:00
ac = bgp_get_af_caps ( & caps , af ) ;
2016-12-07 13:11:28 +00:00
ac - > add_path = pos [ 2 + i + 3 ] ;
}
break ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
case 70 : /* Enhanced route refresh capability, RFC 7313 */
if ( cl ! = 0 )
goto err ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
caps - > enhanced_refresh = 1 ;
break ;
2000-05-04 09:03:31 +00:00
2018-07-31 16:40:38 +00:00
case 71 : /* Long lived graceful restart capability, RFC draft */
if ( cl % 7 )
goto err ;
/* Presumably, only the last instance is valid */
WALK_AF_CAPS ( caps , ac )
{
ac - > llgr_able = 0 ;
ac - > llgr_flags = 0 ;
ac - > llgr_time = 0 ;
}
caps - > llgr_aware = 1 ;
for ( i = 0 ; i < cl ; i + = 7 )
{
af = get_af3 ( pos + 2 + i ) ;
2019-08-21 15:16:08 +00:00
ac = bgp_get_af_caps ( & caps , af ) ;
2018-07-31 16:40:38 +00:00
ac - > llgr_able = 1 ;
ac - > llgr_flags = pos [ 2 + i + 3 ] ;
ac - > llgr_time = get_u24 ( pos + 2 + i + 4 ) ;
}
break ;
2021-02-10 15:53:57 +00:00
case 73 : /* Hostname, RFC draft */
if ( ( cl < 2 ) | | ( cl < 2 + pos [ 2 ] ) )
goto err ;
int length = pos [ 2 ] ;
char * hostname = mb_allocz ( p - > p . pool , length + 1 ) ;
memcpy ( hostname , pos + 3 , length ) ;
hostname [ length ] = 0 ;
for ( i = 0 ; i < length ; i + + )
if ( hostname [ i ] < ' ' )
hostname [ i ] = ' ' ;
caps - > hostname = hostname ;
2016-12-07 13:11:28 +00:00
/* We can safely ignore all other capabilities */
}
ADVANCE ( pos , len , 2 + cl ) ;
}
2018-07-31 16:40:38 +00:00
/* The LLGR capability must be advertised together with the GR capability,
otherwise it must be disregarded */
if ( ! caps - > gr_aware & & caps - > llgr_aware )
{
caps - > llgr_aware = 0 ;
WALK_AF_CAPS ( caps , ac )
{
ac - > llgr_able = 0 ;
ac - > llgr_flags = 0 ;
ac - > llgr_time = 0 ;
}
}
2019-08-21 15:16:08 +00:00
conn - > remote_caps = caps ;
2019-08-20 17:12:59 +00:00
return 0 ;
2016-12-07 13:11:28 +00:00
err :
2019-08-21 15:16:08 +00:00
mb_free ( caps ) ;
2022-07-11 15:19:34 +00:00
bgp_error ( conn , 2 , err_subcode , NULL , 0 ) ;
2019-08-20 17:12:59 +00:00
return - 1 ;
2012-01-08 14:28:27 +00:00
}
2019-03-19 16:44:50 +00:00
static int
bgp_check_capabilities ( struct bgp_conn * conn )
{
struct bgp_proto * p = conn - > bgp ;
struct bgp_caps * local = conn - > local_caps ;
struct bgp_caps * remote = conn - > remote_caps ;
struct bgp_channel * c ;
int count = 0 ;
/* This is partially overlapping with bgp_conn_enter_established_state(),
but we need to run this just after we receive OPEN message */
2022-09-08 17:41:02 +00:00
BGP_WALK_CHANNELS ( p , c )
2019-03-19 16:44:50 +00:00
{
const struct bgp_af_caps * loc = bgp_find_af_caps ( local , c - > afi ) ;
const struct bgp_af_caps * rem = bgp_find_af_caps ( remote , c - > afi ) ;
/* Find out whether this channel will be active */
int active = loc & & loc - > ready & &
( ( rem & & rem - > ready ) | | ( ! remote - > length & & ( c - > afi = = BGP_AF_IPV4 ) ) ) ;
/* Mandatory must be active */
if ( c - > cf - > mandatory & & ! active )
return 0 ;
if ( active )
count + + ;
}
/* We need at least one channel active */
if ( ! count )
return 0 ;
return 1 ;
}
2016-12-07 13:11:28 +00:00
static int
2019-08-20 17:12:59 +00:00
bgp_read_options ( struct bgp_conn * conn , byte * pos , uint len , uint rest )
2000-05-04 09:03:31 +00:00
{
2000-05-04 20:02:56 +00:00
struct bgp_proto * p = conn - > bgp ;
2019-08-20 17:12:59 +00:00
int ext = 0 ;
2023-02-19 14:35:07 +00:00
/* Handle extended length, RFC 9072 */
2019-08-20 17:12:59 +00:00
if ( ( len > 0 ) & & ( rest > 0 ) & & ( pos [ 0 ] = = 255 ) )
{
if ( rest < 3 )
goto err ;
/* Update pos/len to describe optional data */
len = get_u16 ( pos + 1 ) ;
ext = 1 ;
pos + = 3 ;
rest - = 3 ;
}
/* Verify that optional data fits into OPEN packet */
if ( len > rest )
goto err ;
2000-05-04 20:02:56 +00:00
2019-08-20 17:12:59 +00:00
/* Length of option parameter header */
uint hlen = ext ? 3 : 2 ;
2016-12-07 13:11:28 +00:00
while ( len > 0 )
{
2019-08-20 17:12:59 +00:00
if ( len < hlen )
goto err ;
2016-12-07 13:11:28 +00:00
2019-08-20 17:12:59 +00:00
uint otype = get_u8 ( pos ) ;
uint olen = ext ? get_u16 ( pos + 1 ) : get_u8 ( pos + 1 ) ;
if ( len < ( hlen + olen ) )
goto err ;
if ( otype = = 2 )
2000-05-04 20:02:56 +00:00
{
2016-12-07 13:11:28 +00:00
/* BGP capabilities, RFC 5492 */
if ( p - > cf - > capabilities )
2019-08-21 15:16:08 +00:00
if ( bgp_read_capabilities ( conn , pos + hlen , olen ) < 0 )
2019-08-20 17:12:59 +00:00
return - 1 ;
2000-05-04 20:02:56 +00:00
}
2016-12-07 13:11:28 +00:00
else
2000-05-04 20:02:56 +00:00
{
2016-12-07 13:11:28 +00:00
/* Unknown option */
2019-08-20 17:12:59 +00:00
bgp_error ( conn , 2 , 4 , pos , hlen + olen ) ;
2016-12-07 13:11:28 +00:00
return - 1 ;
2000-05-04 20:02:56 +00:00
}
2019-08-20 17:12:59 +00:00
ADVANCE ( pos , len , hlen + olen ) ;
2016-12-07 13:11:28 +00:00
}
2019-08-21 15:16:08 +00:00
/* Prepare empty caps if no capability option was announced */
if ( ! conn - > remote_caps )
2023-05-18 23:02:57 +00:00
conn - > remote_caps = bgp_alloc_capabilities ( p , 0 ) ;
2016-12-07 13:11:28 +00:00
return 0 ;
2019-08-20 17:12:59 +00:00
err :
bgp_error ( conn , 2 , 0 , NULL , 0 ) ;
return - 1 ;
2000-05-04 09:03:31 +00:00
}
2023-04-28 17:13:56 +00:00
static byte *
bgp_copy_open ( struct bgp_proto * p , const byte * pkt , uint len )
{
char * buf = mb_alloc ( p - > p . pool , len - BGP_HEADER_LENGTH ) ;
memcpy ( buf , pkt + BGP_HEADER_LENGTH , len - BGP_HEADER_LENGTH ) ;
return buf ;
}
2014-03-20 13:07:12 +00:00
static byte *
2016-12-07 13:11:28 +00:00
bgp_create_open ( struct bgp_conn * conn , byte * buf )
2014-03-20 13:07:12 +00:00
{
struct bgp_proto * p = conn - > bgp ;
2016-12-07 13:11:28 +00:00
BGP_TRACE ( D_PACKETS , " Sending OPEN(ver=%d,as=%d,hold=%d,id=%08x) " ,
BGP_VERSION , p - > public_as , p - > cf - > hold_time , p - > local_id ) ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
buf [ 0 ] = BGP_VERSION ;
put_u16 ( buf + 1 , ( p - > public_as < 0xFFFF ) ? p - > public_as : AS_TRANS ) ;
put_u16 ( buf + 3 , p - > cf - > hold_time ) ;
put_u32 ( buf + 5 , p - > local_id ) ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
if ( p - > cf - > capabilities )
{
/* Prepare local_caps and write capabilities to buffer */
2019-08-20 17:12:59 +00:00
byte * pos = buf + 12 ;
byte * end = bgp_write_capabilities ( conn , pos ) ;
uint len = end - pos ;
2000-05-04 09:03:31 +00:00
2019-08-20 17:12:59 +00:00
if ( len < 254 )
{
buf [ 9 ] = len + 2 ; /* Optional parameters length */
buf [ 10 ] = 2 ; /* Option 2: Capability list */
buf [ 11 ] = len ; /* Option data length */
}
2023-02-19 14:35:07 +00:00
else /* Extended length, RFC 9072 */
2019-08-20 17:12:59 +00:00
{
/* Move capabilities 4 B forward */
memmove ( buf + 16 , pos , len ) ;
pos = buf + 16 ;
end = pos + len ;
buf [ 9 ] = 255 ; /* Non-ext OP length, fake */
buf [ 10 ] = 255 ; /* Non-ext OP type, signals extended length */
put_u16 ( buf + 11 , len + 3 ) ; /* Extended optional parameters length */
buf [ 13 ] = 2 ; /* Option 2: Capability list */
put_u16 ( buf + 14 , len ) ; /* Option extended data length */
}
2009-11-26 19:47:59 +00:00
2016-12-07 13:11:28 +00:00
return end ;
}
else
{
buf [ 9 ] = 0 ; /* No optional parameters */
return buf + 10 ;
}
2015-03-29 16:27:13 +00:00
return buf ;
}
2016-12-07 13:11:28 +00:00
static void
bgp_rx_open ( struct bgp_conn * conn , byte * pkt , uint len )
2015-03-29 16:27:13 +00:00
{
struct bgp_proto * p = conn - > bgp ;
2016-12-07 13:11:28 +00:00
struct bgp_conn * other ;
u32 asn , hold , id ;
2015-03-29 16:27:13 +00:00
2016-12-07 13:11:28 +00:00
/* Check state */
if ( conn - > state ! = BS_OPENSENT )
{ bgp_error ( conn , 5 , fsm_err_subcode [ conn - > state ] , NULL , 0 ) ; return ; }
2015-03-29 16:27:13 +00:00
2019-08-20 17:12:59 +00:00
/* Check message length */
if ( len < 29 )
2016-12-07 13:11:28 +00:00
{ bgp_error ( conn , 1 , 2 , pkt + 16 , 2 ) ; return ; }
2015-03-29 16:27:13 +00:00
2016-12-07 13:11:28 +00:00
if ( pkt [ 19 ] ! = BGP_VERSION )
{ u16 val = BGP_VERSION ; bgp_error ( conn , 2 , 1 , ( byte * ) & val , 2 ) ; return ; }
2000-03-21 15:53:50 +00:00
2016-12-07 13:11:28 +00:00
asn = get_u16 ( pkt + 20 ) ;
hold = get_u16 ( pkt + 22 ) ;
id = get_u32 ( pkt + 24 ) ;
BGP_TRACE ( D_PACKETS , " Got OPEN(as=%d,hold=%d,id=%R) " , asn , hold , id ) ;
2023-04-28 17:13:56 +00:00
conn - > remote_open_msg = bgp_copy_open ( p , pkt , len ) ;
conn - > remote_open_length = len - BGP_HEADER_LENGTH ;
2019-08-20 17:12:59 +00:00
if ( bgp_read_options ( conn , pkt + 29 , pkt [ 28 ] , len - 29 ) < 0 )
2016-12-07 13:11:28 +00:00
return ;
2022-12-09 04:51:30 +00:00
/* RFC 4271 4.2 - hold time must be either 0 or at least 3 */
2016-12-07 13:11:28 +00:00
if ( hold > 0 & & hold < 3 )
{ bgp_error ( conn , 2 , 6 , pkt + 22 , 2 ) ; return ; }
2000-03-21 15:53:50 +00:00
2022-12-09 04:51:30 +00:00
/* Compute effective hold and keepalive times */
uint hold_time = MIN ( hold , p - > cf - > hold_time ) ;
uint keepalive_time = p - > cf - > keepalive_time ?
( p - > cf - > keepalive_time * hold_time / p - > cf - > hold_time ) :
hold_time / 3 ;
/* Keepalive time might be rounded down to zero */
if ( hold_time & & ! keepalive_time )
keepalive_time = 1 ;
/* Check effective values against configured minimums */
if ( ( hold_time < p - > cf - > min_hold_time ) | |
( keepalive_time < p - > cf - > min_keepalive_time ) )
{ bgp_error ( conn , 2 , 6 , pkt + 22 , 2 ) ; return ; }
2016-12-07 13:11:28 +00:00
/* RFC 6286 2.2 - router ID is nonzero and AS-wide unique */
if ( ! id | | ( p - > is_internal & & id = = p - > local_id ) )
{ bgp_error ( conn , 2 , 3 , pkt + 24 , - 4 ) ; return ; }
2019-03-19 16:44:50 +00:00
/* RFC 5492 4 - check for required capabilities */
if ( p - > cf - > capabilities & & ! bgp_check_capabilities ( conn ) )
{ bgp_error ( conn , 2 , 7 , NULL , 0 ) ; return ; }
2016-12-07 13:11:28 +00:00
struct bgp_caps * caps = conn - > remote_caps ;
if ( caps - > as4_support )
{
u32 as4 = caps - > as4_number ;
if ( ( as4 ! = asn ) & & ( asn ! = AS_TRANS ) )
log ( L_WARN " %s: Peer advertised inconsistent AS numbers " , p - > p . name ) ;
2019-04-03 13:54:50 +00:00
/* When remote ASN is unspecified, it must be external one */
if ( p - > remote_as ? ( as4 ! = p - > remote_as ) : ( as4 = = p - > local_as ) )
2016-12-07 13:11:28 +00:00
{ as4 = htonl ( as4 ) ; bgp_error ( conn , 2 , 2 , ( byte * ) & as4 , 4 ) ; return ; }
2019-04-03 13:54:50 +00:00
conn - > received_as = as4 ;
2016-12-07 13:11:28 +00:00
}
else
{
2019-04-03 13:54:50 +00:00
if ( p - > remote_as ? ( asn ! = p - > remote_as ) : ( asn = = p - > local_as ) )
2016-12-07 13:11:28 +00:00
{ bgp_error ( conn , 2 , 2 , pkt + 20 , 2 ) ; return ; }
2019-04-03 13:54:50 +00:00
conn - > received_as = asn ;
2016-12-07 13:11:28 +00:00
}
2022-07-11 15:19:34 +00:00
/* RFC 9234 4.2 - check role agreement */
u8 local_role = p - > cf - > local_role ;
u8 neigh_role = caps - > role ;
if ( ( local_role ! = BGP_ROLE_UNDEFINED ) & &
( neigh_role ! = BGP_ROLE_UNDEFINED ) & &
! ( ( local_role = = BGP_ROLE_PEER & & neigh_role = = BGP_ROLE_PEER ) | |
( local_role = = BGP_ROLE_CUSTOMER & & neigh_role = = BGP_ROLE_PROVIDER ) | |
( local_role = = BGP_ROLE_PROVIDER & & neigh_role = = BGP_ROLE_CUSTOMER ) | |
( local_role = = BGP_ROLE_RS_CLIENT & & neigh_role = = BGP_ROLE_RS_SERVER ) | |
( local_role = = BGP_ROLE_RS_SERVER & & neigh_role = = BGP_ROLE_RS_CLIENT ) ) )
2023-01-20 14:55:47 +00:00
{ bgp_error ( conn , 2 , 11 , & neigh_role , - 1 ) ; return ; }
2022-07-11 15:19:34 +00:00
if ( ( p - > cf - > require_roles ) & & ( neigh_role = = BGP_ROLE_UNDEFINED ) )
2023-01-20 14:55:47 +00:00
{ bgp_error ( conn , 2 , 11 , & neigh_role , - 1 ) ; return ; }
2022-07-11 15:19:34 +00:00
2016-12-07 13:11:28 +00:00
/* Check the other connection */
other = ( conn = = & p - > outgoing_conn ) ? & p - > incoming_conn : & p - > outgoing_conn ;
switch ( other - > state )
{
case BS_CONNECT :
case BS_ACTIVE :
/* Stop outgoing connection attempts */
bgp_conn_enter_idle_state ( other ) ;
break ;
case BS_IDLE :
case BS_OPENSENT :
case BS_CLOSE :
break ;
case BS_OPENCONFIRM :
/*
* Description of collision detection rules in RFC 4271 is confusing and
* contradictory , but it is essentially :
*
* 1. Router with higher ID is dominant
* 2. If both have the same ID , router with higher ASN is dominant [ RFC6286 ]
* 3. When both connections are in OpenConfirm state , one initiated by
* the dominant router is kept .
*
* The first line in the expression below evaluates whether the neighbor
* is dominant , the second line whether the new connection was initiated
* by the neighbor . If both are true ( or both are false ) , we keep the new
* connection , otherwise we keep the old one .
*/
if ( ( ( p - > local_id < id ) | | ( ( p - > local_id = = id ) & & ( p - > public_as < p - > remote_as ) ) )
= = ( conn = = & p - > incoming_conn ) )
2000-05-08 14:53:22 +00:00
{
2016-12-07 13:11:28 +00:00
/* Should close the other connection */
BGP_TRACE ( D_EVENTS , " Connection collision, giving up the other connection " ) ;
bgp_error ( other , 6 , 7 , NULL , 0 ) ;
break ;
2000-05-08 14:53:22 +00:00
}
2016-12-07 13:11:28 +00:00
/* Fall thru */
case BS_ESTABLISHED :
/* Should close this connection */
BGP_TRACE ( D_EVENTS , " Connection collision, giving up this connection " ) ;
bgp_error ( conn , 6 , 7 , NULL , 0 ) ;
return ;
2000-05-08 14:53:22 +00:00
2016-12-07 13:11:28 +00:00
default :
bug ( " bgp_rx_open: Unknown state " ) ;
}
/* Update our local variables */
2022-12-09 04:51:30 +00:00
conn - > hold_time = hold_time ;
conn - > keepalive_time = keepalive_time ;
2016-12-07 13:11:28 +00:00
conn - > as4_session = conn - > local_caps - > as4_support & & caps - > as4_support ;
conn - > ext_messages = conn - > local_caps - > ext_messages & & caps - > ext_messages ;
p - > remote_id = id ;
DBG ( " BGP: Hold timer set to %d, keepalive to %d, AS to %d, ID to %x, AS4 session to %d \n " ,
conn - > hold_time , conn - > keepalive_time , p - > remote_as , p - > remote_id , conn - > as4_session ) ;
bgp_schedule_packet ( conn , NULL , PKT_KEEPALIVE ) ;
bgp_start_timer ( conn - > hold_timer , conn - > hold_time ) ;
bgp_conn_enter_openconfirm_state ( conn ) ;
}
/*
* Next hop handling
*/
# define REPORT(msg, args...) \
( { log ( L_REMOTE " %s: " msg , s - > proto - > p . name , # # args ) ; } )
2017-02-07 14:55:51 +00:00
# define DISCARD(msg, args...) \
( { REPORT ( msg , # # args ) ; return ; } )
2016-12-07 13:11:28 +00:00
# define WITHDRAW(msg, args...) \
( { REPORT ( msg , # # args ) ; s - > err_withdraw = 1 ; return ; } )
2022-01-28 04:35:22 +00:00
# define REJECT(msg, args...) \
( { log ( L_ERR " %s: " msg , s - > proto - > p . name , # # args ) ; s - > err_reject = 1 ; return ; } )
2017-02-07 14:55:51 +00:00
# define BAD_AFI "Unexpected AF <%u / %u> in UPDATE"
2016-12-07 13:11:28 +00:00
# define BAD_NEXT_HOP "Invalid NEXT_HOP attribute"
# define NO_NEXT_HOP "Missing NEXT_HOP attribute"
2017-03-22 14:00:07 +00:00
# define NO_LABEL_STACK "Missing MPLS stack"
2016-12-07 13:11:28 +00:00
2022-01-28 04:03:03 +00:00
# define MISMATCHED_AF " - mismatched address family (%I for %s)"
2016-12-07 13:11:28 +00:00
static void
bgp_apply_next_hop ( struct bgp_parse_state * s , rta * a , ip_addr gw , ip_addr ll )
{
struct bgp_proto * p = s - > proto ;
struct bgp_channel * c = s - > channel ;
if ( c - > cf - > gw_mode = = GW_DIRECT )
{
neighbor * nbr = NULL ;
/* GW_DIRECT -> single_hop -> p->neigh != NULL */
2022-01-28 04:03:03 +00:00
if ( ipa_nonzero2 ( gw ) )
2018-06-27 14:51:53 +00:00
nbr = neigh_find ( & p - > p , gw , NULL , 0 ) ;
2016-12-07 13:11:28 +00:00
else if ( ipa_nonzero ( ll ) )
2018-06-27 14:51:53 +00:00
nbr = neigh_find ( & p - > p , ll , p - > neigh - > iface , 0 ) ;
2022-01-28 04:03:03 +00:00
else
WITHDRAW ( BAD_NEXT_HOP " - zero address " ) ;
if ( ! nbr )
WITHDRAW ( BAD_NEXT_HOP " - address %I not directly reachable " , ipa_nonzero ( gw ) ? gw : ll ) ;
2016-12-07 13:11:28 +00:00
2022-01-28 04:03:03 +00:00
if ( nbr - > scope = = SCOPE_HOST )
WITHDRAW ( BAD_NEXT_HOP " - address %I is local " , nbr - > addr ) ;
2016-12-07 13:11:28 +00:00
2016-05-06 13:48:35 +00:00
a - > dest = RTD_UNICAST ;
2017-03-22 14:00:07 +00:00
a - > nh . gw = nbr - > addr ;
a - > nh . iface = nbr - > iface ;
2019-09-28 12:17:20 +00:00
a - > igp_metric = c - > cf - > cost ;
2016-12-07 13:11:28 +00:00
}
else /* GW_RECURSIVE */
{
2022-01-28 04:03:03 +00:00
if ( ipa_zero2 ( gw ) )
WITHDRAW ( BAD_NEXT_HOP " - zero address " ) ;
2016-12-07 13:11:28 +00:00
2017-03-26 17:20:15 +00:00
rtable * tab = ipa_is_ip4 ( gw ) ? c - > igp_table_ip4 : c - > igp_table_ip6 ;
2022-10-10 03:06:19 +00:00
ip_addr lla = ( c - > cf - > next_hop_prefer = = NHP_LOCAL ) ? ll : IPA_NONE ;
s - > hostentry = rt_get_hostentry ( tab , gw , lla , c - > c . table ) ;
2017-03-22 14:00:07 +00:00
if ( ! s - > mpls )
rta_apply_hostentry ( a , s - > hostentry , NULL ) ;
/* With MPLS, hostentry is applied later in bgp_apply_mpls_labels() */
}
}
static void
bgp_apply_mpls_labels ( struct bgp_parse_state * s , rta * a , u32 * labels , uint lnum )
{
if ( lnum > MPLS_MAX_LABEL_STACK )
{
REPORT ( " Too many MPLS labels ($u) " , lnum ) ;
a - > dest = RTD_UNREACHABLE ;
a - > hostentry = NULL ;
a - > nh = ( struct nexthop ) { } ;
return ;
}
/* Handle implicit NULL as empty MPLS stack */
if ( ( lnum = = 1 ) & & ( labels [ 0 ] = = BGP_MPLS_NULL ) )
lnum = 0 ;
if ( s - > channel - > cf - > gw_mode = = GW_DIRECT )
{
a - > nh . labels = lnum ;
memcpy ( a - > nh . label , labels , 4 * lnum ) ;
}
else /* GW_RECURSIVE */
{
mpls_label_stack ms ;
ms . len = lnum ;
memcpy ( ms . stack , labels , 4 * lnum ) ;
rta_apply_hostentry ( a , s - > hostentry , & ms ) ;
2016-12-07 13:11:28 +00:00
}
}
2021-12-20 19:25:35 +00:00
static void
bgp_apply_flow_validation ( struct bgp_parse_state * s , const net_addr * n , rta * a )
{
struct bgp_channel * c = s - > channel ;
int valid = rt_flowspec_check ( c - > base_table , c - > c . table , n , a , s - > proto - > is_interior ) ;
a - > dest = valid ? RTD_NONE : RTD_UNREACHABLE ;
/* Invalidate cached rta if dest changes */
if ( s - > cached_rta & & ( s - > cached_rta - > dest ! = a - > dest ) )
{
rta_free ( s - > cached_rta ) ;
s - > cached_rta = NULL ;
}
}
2017-03-22 14:00:07 +00:00
2018-12-16 22:44:24 +00:00
static int
bgp_match_src ( struct bgp_export_state * s , int mode )
{
switch ( mode )
{
case NH_NO : return 0 ;
case NH_ALL : return 1 ;
case NH_IBGP : return s - > src & & s - > src - > is_internal ;
case NH_EBGP : return s - > src & & ! s - > src - > is_internal ;
default : return 0 ;
}
}
2016-12-07 13:11:28 +00:00
static inline int
bgp_use_next_hop ( struct bgp_export_state * s , eattr * a )
{
struct bgp_proto * p = s - > proto ;
2018-12-15 13:01:57 +00:00
struct bgp_channel * c = s - > channel ;
2016-12-07 13:11:28 +00:00
ip_addr * nh = ( void * ) a - > u . ptr - > data ;
2018-12-16 22:44:24 +00:00
/* Handle next hop self option */
if ( c - > cf - > next_hop_self & & bgp_match_src ( s , c - > cf - > next_hop_self ) )
2016-12-07 13:11:28 +00:00
return 0 ;
2018-12-16 22:44:24 +00:00
/* Handle next hop keep option */
if ( c - > cf - > next_hop_keep & & bgp_match_src ( s , c - > cf - > next_hop_keep ) )
2016-12-07 13:11:28 +00:00
return 1 ;
/* Keep it when explicitly set in export filter */
2022-03-14 09:06:44 +00:00
if ( a - > fresh )
2016-12-07 13:11:28 +00:00
return 1 ;
2018-12-15 13:01:57 +00:00
/* Check for non-matching AF */
if ( ( ipa_is_ip4 ( * nh ) ! = bgp_channel_is_ipv4 ( c ) ) & & ! c - > ext_next_hop )
return 0 ;
2022-09-27 14:13:27 +00:00
/* Do not pass NEXT_HOP between different VRFs */
if ( p - > p . vrf_set & & s - > src & & s - > src - > p . vrf_set & & ( p - > p . vrf ! = s - > src - > p . vrf ) )
return 0 ;
2016-12-07 13:11:28 +00:00
/* Keep it when exported to internal peers */
if ( p - > is_interior & & ipa_nonzero ( * nh ) )
return 1 ;
/* Keep it when forwarded between single-hop BGPs on the same iface */
2021-05-31 23:59:20 +00:00
struct iface * ifa = ( s - > src & & s - > src - > neigh & & ( s - > src - > p . proto_state ! = PS_DOWN ) ) ?
s - > src - > neigh - > iface : NULL ;
2016-12-07 13:11:28 +00:00
return p - > neigh & & ( p - > neigh - > iface = = ifa ) ;
}
static inline int
bgp_use_gateway ( struct bgp_export_state * s )
{
struct bgp_proto * p = s - > proto ;
2018-12-15 13:01:57 +00:00
struct bgp_channel * c = s - > channel ;
2016-12-07 13:11:28 +00:00
rta * ra = s - > route - > attrs ;
2018-12-16 22:44:24 +00:00
/* Handle next hop self option - also applies to gateway */
if ( c - > cf - > next_hop_self & & bgp_match_src ( s , c - > cf - > next_hop_self ) )
2016-12-07 13:11:28 +00:00
return 0 ;
2017-02-20 01:26:45 +00:00
/* We need one valid global gateway */
if ( ( ra - > dest ! = RTD_UNICAST ) | | ra - > nh . next | | ipa_zero ( ra - > nh . gw ) | | ipa_is_link_local ( ra - > nh . gw ) )
2016-12-07 13:11:28 +00:00
return 0 ;
2018-12-15 13:01:57 +00:00
/* Check for non-matching AF */
if ( ( ipa_is_ip4 ( ra - > nh . gw ) ! = bgp_channel_is_ipv4 ( c ) ) & & ! c - > ext_next_hop )
return 0 ;
2022-09-27 14:13:27 +00:00
/* Do not use gateway from different VRF */
2023-08-23 13:55:31 +00:00
if ( p - > p . vrf_set & & ra - > nh . iface & & ! if_in_vrf ( ra - > nh . iface , p - > p . vrf ) )
2022-09-27 14:13:27 +00:00
return 0 ;
2016-12-07 13:11:28 +00:00
/* Use it when exported to internal peers */
if ( p - > is_interior )
return 1 ;
/* Use it when forwarded to single-hop BGP peer on on the same iface */
2016-05-06 13:48:35 +00:00
return p - > neigh & & ( p - > neigh - > iface = = ra - > nh . iface ) ;
2016-12-07 13:11:28 +00:00
}
static void
bgp_update_next_hop_ip ( struct bgp_export_state * s , eattr * a , ea_list * * to )
{
if ( ! a | | ! bgp_use_next_hop ( s , a ) )
{
if ( bgp_use_gateway ( s ) )
2000-03-21 15:53:50 +00:00
{
2017-03-22 14:00:07 +00:00
rta * ra = s - > route - > attrs ;
ip_addr nh [ 1 ] = { ra - > nh . gw } ;
2016-12-07 13:11:28 +00:00
bgp_set_attr_data ( to , s - > pool , BA_NEXT_HOP , 0 , nh , 16 ) ;
2017-03-22 14:00:07 +00:00
if ( s - > mpls )
{
u32 implicit_null = BGP_MPLS_NULL ;
u32 * labels = ra - > nh . labels ? ra - > nh . label : & implicit_null ;
uint lnum = ra - > nh . labels ? ra - > nh . labels : 1 ;
bgp_set_attr_data ( to , s - > pool , BA_MPLS_LABEL_STACK , 0 , labels , lnum * 4 ) ;
}
2022-09-27 14:13:27 +00:00
else
bgp_unset_attr ( to , s - > pool , BA_MPLS_LABEL_STACK ) ;
2000-03-21 15:53:50 +00:00
}
2016-12-07 13:11:28 +00:00
else
2000-03-21 15:53:50 +00:00
{
2016-12-07 13:11:28 +00:00
ip_addr nh [ 2 ] = { s - > channel - > next_hop_addr , s - > channel - > link_addr } ;
bgp_set_attr_data ( to , s - > pool , BA_NEXT_HOP , 0 , nh , ipa_nonzero ( nh [ 1 ] ) ? 32 : 16 ) ;
2019-09-28 12:17:20 +00:00
s - > local_next_hop = 1 ;
2017-03-22 14:00:07 +00:00
/* TODO: Use local MPLS assigned label */
if ( s - > mpls )
2018-06-30 23:03:16 +00:00
{
u32 implicit_null = BGP_MPLS_NULL ;
bgp_set_attr_data ( to , s - > pool , BA_MPLS_LABEL_STACK , 0 , & implicit_null , 4 ) ;
}
2022-09-27 14:13:27 +00:00
else
bgp_unset_attr ( to , s - > pool , BA_MPLS_LABEL_STACK ) ;
2000-03-21 15:53:50 +00:00
}
2016-12-07 13:11:28 +00:00
}
/* Check if next hop is valid */
a = bgp_find_attr ( * to , BA_NEXT_HOP ) ;
if ( ! a )
2022-01-28 04:35:22 +00:00
REJECT ( NO_NEXT_HOP ) ;
2016-12-07 13:11:28 +00:00
ip_addr * nh = ( void * ) a - > u . ptr - > data ;
2019-04-02 15:22:31 +00:00
ip_addr peer = s - > proto - > remote_ip ;
2016-12-07 13:11:28 +00:00
uint len = a - > u . ptr - > length ;
2017-03-26 17:20:15 +00:00
/* Forbid zero next hop */
2022-01-28 04:03:03 +00:00
if ( ipa_zero2 ( nh [ 0 ] ) & & ( ( len ! = 32 ) | | ipa_zero ( nh [ 1 ] ) ) )
2022-01-28 04:35:22 +00:00
REJECT ( BAD_NEXT_HOP " - zero address " ) ;
2016-12-07 13:11:28 +00:00
2017-03-26 17:20:15 +00:00
/* Forbid next hop equal to neighbor IP */
2016-12-07 13:11:28 +00:00
if ( ipa_equal ( peer , nh [ 0 ] ) | | ( ( len = = 32 ) & & ipa_equal ( peer , nh [ 1 ] ) ) )
2022-01-28 04:35:22 +00:00
REJECT ( BAD_NEXT_HOP " - neighbor address %I " , peer ) ;
2017-03-22 14:00:07 +00:00
2017-03-26 17:20:15 +00:00
/* Forbid next hop with non-matching AF */
if ( ( ipa_is_ip4 ( nh [ 0 ] ) ! = bgp_channel_is_ipv4 ( s - > channel ) ) & &
! s - > channel - > ext_next_hop )
2022-01-28 04:35:22 +00:00
REJECT ( BAD_NEXT_HOP MISMATCHED_AF , nh [ 0 ] , s - > channel - > desc - > name ) ;
2017-03-26 17:20:15 +00:00
2017-03-22 14:00:07 +00:00
/* Just check if MPLS stack */
if ( s - > mpls & & ! bgp_find_attr ( * to , BA_MPLS_LABEL_STACK ) )
2022-01-28 04:35:22 +00:00
REJECT ( NO_LABEL_STACK ) ;
2016-12-07 13:11:28 +00:00
}
2017-03-26 17:20:15 +00:00
static uint
bgp_encode_next_hop_ip ( struct bgp_write_state * s , eattr * a , byte * buf , uint size UNUSED )
{
/* This function is used only for MP-BGP, see bgp_encode_next_hop() for IPv4 BGP */
ip_addr * nh = ( void * ) a - > u . ptr - > data ;
uint len = a - > u . ptr - > length ;
ASSERT ( ( len = = 16 ) | | ( len = = 32 ) ) ;
/*
* Both IPv4 and IPv6 next hops can be used ( with ext_next_hop enabled ) . This
2023-08-22 12:20:59 +00:00
* is specified in RFC 8950 for IPv4 and in RFC 4798 for IPv6 . The difference
2017-03-26 17:20:15 +00:00
* is that IPv4 address is directly encoded with IPv4 NLRI , but as IPv4 - mapped
* IPv6 address with IPv6 NLRI .
*/
if ( bgp_channel_is_ipv4 ( s - > channel ) & & ipa_is_ip4 ( nh [ 0 ] ) )
{
put_ip4 ( buf , ipa_to_ip4 ( nh [ 0 ] ) ) ;
return 4 ;
}
put_ip6 ( buf , ipa_to_ip6 ( nh [ 0 ] ) ) ;
if ( len = = 32 )
put_ip6 ( buf + 16 , ipa_to_ip6 ( nh [ 1 ] ) ) ;
return len ;
}
static void
bgp_decode_next_hop_ip ( struct bgp_parse_state * s , byte * data , uint len , rta * a )
{
struct bgp_channel * c = s - > channel ;
struct adata * ad = lp_alloc_adata ( s - > pool , 32 ) ;
ip_addr * nh = ( void * ) ad - > data ;
if ( len = = 4 )
{
nh [ 0 ] = ipa_from_ip4 ( get_ip4 ( data ) ) ;
nh [ 1 ] = IPA_NONE ;
}
else if ( len = = 16 )
{
nh [ 0 ] = ipa_from_ip6 ( get_ip6 ( data ) ) ;
nh [ 1 ] = IPA_NONE ;
if ( ipa_is_link_local ( nh [ 0 ] ) )
{ nh [ 1 ] = nh [ 0 ] ; nh [ 0 ] = IPA_NONE ; }
}
else if ( len = = 32 )
{
nh [ 0 ] = ipa_from_ip6 ( get_ip6 ( data ) ) ;
nh [ 1 ] = ipa_from_ip6 ( get_ip6 ( data + 16 ) ) ;
2020-04-29 00:50:29 +00:00
if ( ipa_is_link_local ( nh [ 0 ] ) )
{ nh [ 1 ] = nh [ 0 ] ; nh [ 0 ] = IPA_NONE ; }
if ( ipa_is_ip4 ( nh [ 0 ] ) | | ! ipa_is_link_local ( nh [ 1 ] ) )
2017-03-26 17:20:15 +00:00
nh [ 1 ] = IPA_NONE ;
}
else
bgp_parse_error ( s , 9 ) ;
if ( ipa_zero ( nh [ 1 ] ) )
ad - > length = 16 ;
if ( ( bgp_channel_is_ipv4 ( c ) ! = ipa_is_ip4 ( nh [ 0 ] ) ) & & ! c - > ext_next_hop )
2022-01-28 04:03:03 +00:00
WITHDRAW ( BAD_NEXT_HOP MISMATCHED_AF , nh [ 0 ] , c - > desc - > name ) ;
2017-03-26 17:20:15 +00:00
// XXXX validate next hop
bgp_set_attr_ptr ( & ( a - > eattrs ) , s - > pool , BA_NEXT_HOP , 0 , ad ) ;
bgp_apply_next_hop ( s , a , nh [ 0 ] , nh [ 1 ] ) ;
}
static uint
bgp_encode_next_hop_vpn ( struct bgp_write_state * s , eattr * a , byte * buf , uint size UNUSED )
{
ip_addr * nh = ( void * ) a - > u . ptr - > data ;
uint len = a - > u . ptr - > length ;
ASSERT ( ( len = = 16 ) | | ( len = = 32 ) ) ;
/*
* Both IPv4 and IPv6 next hops can be used ( with ext_next_hop enabled ) . This
2023-08-22 12:20:59 +00:00
* is specified in RFC 8950 for VPNv4 and in RFC 4659 for VPNv6 . The difference
2017-03-26 17:20:15 +00:00
* is that IPv4 address is directly encoded with VPNv4 NLRI , but as IPv4 - mapped
* IPv6 address with VPNv6 NLRI .
*/
if ( bgp_channel_is_ipv4 ( s - > channel ) & & ipa_is_ip4 ( nh [ 0 ] ) )
{
put_u64 ( buf , 0 ) ; /* VPN RD is 0 */
put_ip4 ( buf + 8 , ipa_to_ip4 ( nh [ 0 ] ) ) ;
return 12 ;
}
put_u64 ( buf , 0 ) ; /* VPN RD is 0 */
put_ip6 ( buf + 8 , ipa_to_ip6 ( nh [ 0 ] ) ) ;
if ( len = = 16 )
return 24 ;
put_u64 ( buf + 24 , 0 ) ; /* VPN RD is 0 */
put_ip6 ( buf + 32 , ipa_to_ip6 ( nh [ 1 ] ) ) ;
return 48 ;
}
static void
bgp_decode_next_hop_vpn ( struct bgp_parse_state * s , byte * data , uint len , rta * a )
{
struct bgp_channel * c = s - > channel ;
struct adata * ad = lp_alloc_adata ( s - > pool , 32 ) ;
ip_addr * nh = ( void * ) ad - > data ;
if ( len = = 12 )
{
nh [ 0 ] = ipa_from_ip4 ( get_ip4 ( data + 8 ) ) ;
nh [ 1 ] = IPA_NONE ;
}
else if ( len = = 24 )
{
nh [ 0 ] = ipa_from_ip6 ( get_ip6 ( data + 8 ) ) ;
nh [ 1 ] = IPA_NONE ;
if ( ipa_is_link_local ( nh [ 0 ] ) )
{ nh [ 1 ] = nh [ 0 ] ; nh [ 0 ] = IPA_NONE ; }
}
else if ( len = = 48 )
{
nh [ 0 ] = ipa_from_ip6 ( get_ip6 ( data + 8 ) ) ;
nh [ 1 ] = ipa_from_ip6 ( get_ip6 ( data + 32 ) ) ;
if ( ipa_is_ip4 ( nh [ 0 ] ) | | ! ip6_is_link_local ( nh [ 1 ] ) )
nh [ 1 ] = IPA_NONE ;
}
else
bgp_parse_error ( s , 9 ) ;
if ( ipa_zero ( nh [ 1 ] ) )
ad - > length = 16 ;
/* XXXX which error */
if ( ( get_u64 ( data ) ! = 0 ) | | ( ( len = = 48 ) & & ( get_u64 ( data + 24 ) ! = 0 ) ) )
bgp_parse_error ( s , 9 ) ;
if ( ( bgp_channel_is_ipv4 ( c ) ! = ipa_is_ip4 ( nh [ 0 ] ) ) & & ! c - > ext_next_hop )
2022-01-28 04:03:03 +00:00
WITHDRAW ( BAD_NEXT_HOP MISMATCHED_AF , nh [ 0 ] , c - > desc - > name ) ;
2017-03-26 17:20:15 +00:00
// XXXX validate next hop
bgp_set_attr_ptr ( & ( a - > eattrs ) , s - > pool , BA_NEXT_HOP , 0 , ad ) ;
bgp_apply_next_hop ( s , a , nh [ 0 ] , nh [ 1 ] ) ;
}
2016-12-07 17:28:07 +00:00
static uint
bgp_encode_next_hop_none ( struct bgp_write_state * s UNUSED , eattr * a UNUSED , byte * buf UNUSED , uint size UNUSED )
{
return 0 ;
}
static void
bgp_decode_next_hop_none ( struct bgp_parse_state * s UNUSED , byte * data UNUSED , uint len UNUSED , rta * a UNUSED )
{
2017-02-07 14:55:51 +00:00
/*
* Although we expect no next hop and RFC 7606 7.11 states that attribute
* MP_REACH_NLRI with unexpected next hop length is considered malformed ,
* FlowSpec RFC 5575 4 states that next hop shall be ignored on receipt .
*/
2016-12-07 17:28:07 +00:00
return ;
}
static void
2017-02-07 14:55:51 +00:00
bgp_update_next_hop_none ( struct bgp_export_state * s , eattr * a , ea_list * * to )
2016-12-07 17:28:07 +00:00
{
2017-02-07 14:55:51 +00:00
/* NEXT_HOP shall not pass */
if ( a )
bgp_unset_attr ( to , s - > pool , BA_NEXT_HOP ) ;
2016-12-07 17:28:07 +00:00
}
2016-12-07 13:11:28 +00:00
/*
* UPDATE
*/
static void
2022-01-24 02:44:21 +00:00
bgp_rte_update ( struct bgp_parse_state * s , const net_addr * n , u32 path_id , rta * a0 )
2016-12-07 13:11:28 +00:00
{
if ( path_id ! = s - > last_id )
{
s - > last_src = rt_get_source ( & s - > proto - > p , path_id ) ;
s - > last_id = path_id ;
rta_free ( s - > cached_rta ) ;
s - > cached_rta = NULL ;
}
if ( ! a0 )
{
2022-01-24 02:44:21 +00:00
/* Route update was changed to withdraw */
if ( s - > err_withdraw & & s - > reach_nlri_step )
REPORT ( " Invalid route %N withdrawn " , n ) ;
2016-12-07 13:11:28 +00:00
/* Route withdraw */
2018-09-27 20:57:55 +00:00
rte_update3 ( & s - > channel - > c , n , NULL , s - > last_src ) ;
2016-12-07 13:11:28 +00:00
return ;
}
/* Prepare cached route attributes */
if ( s - > cached_rta = = NULL )
{
/* Workaround for rta_lookup() breaking eattrs */
ea_list * ea = a0 - > eattrs ;
s - > cached_rta = rta_lookup ( a0 ) ;
a0 - > eattrs = ea ;
}
rta * a = rta_clone ( s - > cached_rta ) ;
2020-04-10 15:08:29 +00:00
rte * e = rte_get_temp ( a , s - > last_src ) ;
2016-12-07 13:11:28 +00:00
2018-09-27 20:57:55 +00:00
rte_update3 ( & s - > channel - > c , n , e , s - > last_src ) ;
2016-12-07 13:11:28 +00:00
}
2017-03-22 14:00:07 +00:00
static void
2018-12-27 13:26:11 +00:00
bgp_encode_mpls_labels ( struct bgp_write_state * s UNUSED , const adata * mpls , byte * * pos , uint * size , byte * pxlen )
2017-03-22 14:00:07 +00:00
{
2018-12-27 13:26:11 +00:00
const u32 dummy = 0 ;
const u32 * labels = mpls ? ( const u32 * ) mpls - > data : & dummy ;
2017-03-22 14:00:07 +00:00
uint lnum = mpls ? ( mpls - > length / 4 ) : 1 ;
for ( uint i = 0 ; i < lnum ; i + + )
{
put_u24 ( * pos , labels [ i ] < < 4 ) ;
ADVANCE ( * pos , * size , 3 ) ;
}
/* Add bottom-of-stack flag */
( * pos ) [ - 1 ] | = BGP_MPLS_BOS ;
* pxlen + = 24 * lnum ;
}
static void
bgp_decode_mpls_labels ( struct bgp_parse_state * s , byte * * pos , uint * len , uint * pxlen , rta * a )
{
u32 labels [ BGP_MPLS_MAX ] , label ;
uint lnum = 0 ;
do {
if ( * pxlen < 24 )
bgp_parse_error ( s , 1 ) ;
label = get_u24 ( * pos ) ;
labels [ lnum + + ] = label > > 4 ;
ADVANCE ( * pos , * len , 3 ) ;
* pxlen - = 24 ;
2016-12-07 13:11:28 +00:00
2018-06-30 22:43:24 +00:00
/* RFC 8277 2.4 - withdraw does not have variable-size MPLS stack but
fixed - size 24 - bit Compatibility field , which MUST be ignored */
2022-01-28 17:13:18 +00:00
if ( ! s - > reach_nlri_step )
2018-06-30 22:43:24 +00:00
return ;
2017-03-22 14:00:07 +00:00
}
while ( ! ( label & BGP_MPLS_BOS ) ) ;
if ( ! a )
return ;
/* Attach MPLS attribute unless we already have one */
if ( ! s - > mpls_labels )
{
s - > mpls_labels = lp_alloc_adata ( s - > pool , 4 * BGP_MPLS_MAX ) ;
bgp_set_attr_ptr ( & ( a - > eattrs ) , s - > pool , BA_MPLS_LABEL_STACK , 0 , s - > mpls_labels ) ;
}
/* Overwrite data in the attribute */
s - > mpls_labels - > length = 4 * lnum ;
memcpy ( s - > mpls_labels - > data , labels , 4 * lnum ) ;
/* Update next hop entry in rta */
bgp_apply_mpls_labels ( s , a , labels , lnum ) ;
/* Attributes were changed, invalidate cached entry */
rta_free ( s - > cached_rta ) ;
s - > cached_rta = NULL ;
return ;
}
2016-12-07 13:11:28 +00:00
static uint
bgp_encode_nlri_ip4 ( struct bgp_write_state * s , struct bgp_bucket * buck , byte * buf , uint size )
{
byte * pos = buf ;
2017-03-22 14:00:07 +00:00
while ( ! EMPTY_LIST ( buck - > prefixes ) & & ( size > = BGP_NLRI_MAX ) )
2016-12-07 13:11:28 +00:00
{
struct bgp_prefix * px = HEAD ( buck - > prefixes ) ;
struct net_addr_ip4 * net = ( void * ) px - > net ;
/* Encode path ID */
if ( s - > add_path )
2000-03-21 15:53:50 +00:00
{
2016-12-07 13:11:28 +00:00
put_u32 ( pos , px - > path_id ) ;
ADVANCE ( pos , size , 4 ) ;
2000-03-21 15:53:50 +00:00
}
2016-12-07 13:11:28 +00:00
/* Encode prefix length */
* pos = net - > pxlen ;
ADVANCE ( pos , size , 1 ) ;
2017-03-22 14:00:07 +00:00
/* Encode MPLS labels */
if ( s - > mpls )
bgp_encode_mpls_labels ( s , s - > mpls_labels , & pos , & size , pos - 1 ) ;
2016-12-07 13:11:28 +00:00
/* Encode prefix body */
2017-03-22 14:00:07 +00:00
ip4_addr a = ip4_hton ( net - > prefix ) ;
uint b = ( net - > pxlen + 7 ) / 8 ;
2016-12-07 13:11:28 +00:00
memcpy ( pos , & a , b ) ;
ADVANCE ( pos , size , b ) ;
2021-03-29 02:43:04 +00:00
if ( ! s - > sham )
bgp_free_prefix ( s - > channel , px ) ;
else
rem_node ( & px - > buck_node ) ;
2016-12-07 13:11:28 +00:00
}
return pos - buf ;
}
static void
bgp_decode_nlri_ip4 ( struct bgp_parse_state * s , byte * pos , uint len , rta * a )
{
while ( len )
{
net_addr_ip4 net ;
u32 path_id = 0 ;
/* Decode path ID */
if ( s - > add_path )
2000-03-21 15:53:50 +00:00
{
2016-12-07 13:11:28 +00:00
if ( len < 5 )
bgp_parse_error ( s , 1 ) ;
path_id = get_u32 ( pos ) ;
ADVANCE ( pos , len , 4 ) ;
2000-03-21 15:53:50 +00:00
}
2016-12-07 13:11:28 +00:00
/* Decode prefix length */
uint l = * pos ;
ADVANCE ( pos , len , 1 ) ;
2017-03-22 14:00:07 +00:00
if ( len < ( ( l + 7 ) / 8 ) )
bgp_parse_error ( s , 1 ) ;
/* Decode MPLS labels */
if ( s - > mpls )
bgp_decode_mpls_labels ( s , & pos , & len , & l , a ) ;
2016-12-07 13:11:28 +00:00
if ( l > IP4_MAX_PREFIX_LENGTH )
bgp_parse_error ( s , 10 ) ;
/* Decode prefix body */
ip4_addr addr = IP4_NONE ;
2017-03-22 14:00:07 +00:00
uint b = ( l + 7 ) / 8 ;
2016-12-07 13:11:28 +00:00
memcpy ( & addr , pos , b ) ;
ADVANCE ( pos , len , b ) ;
net = NET_ADDR_IP4 ( ip4_ntoh ( addr ) , l ) ;
net_normalize_ip4 ( & net ) ;
// XXXX validate prefix
bgp_rte_update ( s , ( net_addr * ) & net , path_id , a ) ;
}
}
static uint
bgp_encode_nlri_ip6 ( struct bgp_write_state * s , struct bgp_bucket * buck , byte * buf , uint size )
{
byte * pos = buf ;
2017-03-22 14:00:07 +00:00
while ( ! EMPTY_LIST ( buck - > prefixes ) & & ( size > = BGP_NLRI_MAX ) )
2016-12-07 13:11:28 +00:00
{
struct bgp_prefix * px = HEAD ( buck - > prefixes ) ;
struct net_addr_ip6 * net = ( void * ) px - > net ;
/* Encode path ID */
if ( s - > add_path )
2009-11-26 19:47:59 +00:00
{
2016-12-07 13:11:28 +00:00
put_u32 ( pos , px - > path_id ) ;
ADVANCE ( pos , size , 4 ) ;
2009-11-26 19:47:59 +00:00
}
2016-12-07 13:11:28 +00:00
/* Encode prefix length */
* pos = net - > pxlen ;
ADVANCE ( pos , size , 1 ) ;
2017-03-22 14:00:07 +00:00
/* Encode MPLS labels */
if ( s - > mpls )
bgp_encode_mpls_labels ( s , s - > mpls_labels , & pos , & size , pos - 1 ) ;
2016-12-07 13:11:28 +00:00
/* Encode prefix body */
2017-03-22 14:00:07 +00:00
ip6_addr a = ip6_hton ( net - > prefix ) ;
uint b = ( net - > pxlen + 7 ) / 8 ;
2016-12-07 13:11:28 +00:00
memcpy ( pos , & a , b ) ;
ADVANCE ( pos , size , b ) ;
2021-03-29 02:43:04 +00:00
if ( ! s - > sham )
bgp_free_prefix ( s - > channel , px ) ;
else
rem_node ( & px - > buck_node ) ;
2016-12-07 13:11:28 +00:00
}
return pos - buf ;
}
static void
bgp_decode_nlri_ip6 ( struct bgp_parse_state * s , byte * pos , uint len , rta * a )
{
while ( len )
{
net_addr_ip6 net ;
u32 path_id = 0 ;
/* Decode path ID */
if ( s - > add_path )
2015-03-29 16:27:13 +00:00
{
2016-12-07 13:11:28 +00:00
if ( len < 5 )
bgp_parse_error ( s , 1 ) ;
path_id = get_u32 ( pos ) ;
ADVANCE ( pos , len , 4 ) ;
2015-03-29 16:27:13 +00:00
}
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
/* Decode prefix length */
uint l = * pos ;
ADVANCE ( pos , len , 1 ) ;
2015-03-29 16:27:13 +00:00
2017-03-22 14:00:07 +00:00
if ( len < ( ( l + 7 ) / 8 ) )
bgp_parse_error ( s , 1 ) ;
/* Decode MPLS labels */
if ( s - > mpls )
bgp_decode_mpls_labels ( s , & pos , & len , & l , a ) ;
2016-12-07 13:11:28 +00:00
if ( l > IP6_MAX_PREFIX_LENGTH )
bgp_parse_error ( s , 10 ) ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
/* Decode prefix body */
ip6_addr addr = IP6_NONE ;
2017-03-22 14:00:07 +00:00
uint b = ( l + 7 ) / 8 ;
2016-12-07 13:11:28 +00:00
memcpy ( & addr , pos , b ) ;
ADVANCE ( pos , len , b ) ;
2015-03-29 16:27:13 +00:00
2016-12-07 13:11:28 +00:00
net = NET_ADDR_IP6 ( ip6_ntoh ( addr ) , l ) ;
net_normalize_ip6 ( & net ) ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
// XXXX validate prefix
2015-03-29 16:27:13 +00:00
2016-12-07 13:11:28 +00:00
bgp_rte_update ( s , ( net_addr * ) & net , path_id , a ) ;
}
2000-03-21 15:53:50 +00:00
}
2017-03-22 14:00:07 +00:00
static uint
bgp_encode_nlri_vpn4 ( struct bgp_write_state * s , struct bgp_bucket * buck , byte * buf , uint size )
{
byte * pos = buf ;
while ( ! EMPTY_LIST ( buck - > prefixes ) & & ( size > = BGP_NLRI_MAX ) )
{
struct bgp_prefix * px = HEAD ( buck - > prefixes ) ;
struct net_addr_vpn4 * net = ( void * ) px - > net ;
/* Encode path ID */
if ( s - > add_path )
{
put_u32 ( pos , px - > path_id ) ;
ADVANCE ( pos , size , 4 ) ;
}
/* Encode prefix length */
2017-03-23 13:10:42 +00:00
* pos = 64 + net - > pxlen ;
2017-03-22 14:00:07 +00:00
ADVANCE ( pos , size , 1 ) ;
/* Encode MPLS labels */
2017-03-30 12:00:08 +00:00
if ( s - > mpls )
bgp_encode_mpls_labels ( s , s - > mpls_labels , & pos , & size , pos - 1 ) ;
2017-03-22 14:00:07 +00:00
/* Encode route distinguisher */
put_u64 ( pos , net - > rd ) ;
ADVANCE ( pos , size , 8 ) ;
/* Encode prefix body */
ip4_addr a = ip4_hton ( net - > prefix ) ;
uint b = ( net - > pxlen + 7 ) / 8 ;
memcpy ( pos , & a , b ) ;
ADVANCE ( pos , size , b ) ;
2021-03-29 02:43:04 +00:00
if ( ! s - > sham )
bgp_free_prefix ( s - > channel , px ) ;
else
rem_node ( & px - > buck_node ) ;
2017-03-22 14:00:07 +00:00
}
return pos - buf ;
}
static void
bgp_decode_nlri_vpn4 ( struct bgp_parse_state * s , byte * pos , uint len , rta * a )
{
while ( len )
{
net_addr_vpn4 net ;
u32 path_id = 0 ;
/* Decode path ID */
if ( s - > add_path )
{
if ( len < 5 )
bgp_parse_error ( s , 1 ) ;
path_id = get_u32 ( pos ) ;
ADVANCE ( pos , len , 4 ) ;
}
/* Decode prefix length */
uint l = * pos ;
ADVANCE ( pos , len , 1 ) ;
if ( len < ( ( l + 7 ) / 8 ) )
bgp_parse_error ( s , 1 ) ;
/* Decode MPLS labels */
2017-03-30 12:00:08 +00:00
if ( s - > mpls )
bgp_decode_mpls_labels ( s , & pos , & len , & l , a ) ;
2017-03-22 14:00:07 +00:00
/* Decode route distinguisher */
if ( l < 64 )
bgp_parse_error ( s , 1 ) ;
u64 rd = get_u64 ( pos ) ;
ADVANCE ( pos , len , 8 ) ;
l - = 64 ;
if ( l > IP4_MAX_PREFIX_LENGTH )
bgp_parse_error ( s , 10 ) ;
/* Decode prefix body */
ip4_addr addr = IP4_NONE ;
uint b = ( l + 7 ) / 8 ;
memcpy ( & addr , pos , b ) ;
ADVANCE ( pos , len , b ) ;
net = NET_ADDR_VPN4 ( ip4_ntoh ( addr ) , l , rd ) ;
net_normalize_vpn4 ( & net ) ;
// XXXX validate prefix
bgp_rte_update ( s , ( net_addr * ) & net , path_id , a ) ;
}
}
static uint
bgp_encode_nlri_vpn6 ( struct bgp_write_state * s , struct bgp_bucket * buck , byte * buf , uint size )
{
byte * pos = buf ;
while ( ! EMPTY_LIST ( buck - > prefixes ) & & ( size > = BGP_NLRI_MAX ) )
{
struct bgp_prefix * px = HEAD ( buck - > prefixes ) ;
struct net_addr_vpn6 * net = ( void * ) px - > net ;
/* Encode path ID */
if ( s - > add_path )
{
put_u32 ( pos , px - > path_id ) ;
ADVANCE ( pos , size , 4 ) ;
}
/* Encode prefix length */
2017-03-23 13:10:42 +00:00
* pos = 64 + net - > pxlen ;
2017-03-22 14:00:07 +00:00
ADVANCE ( pos , size , 1 ) ;
/* Encode MPLS labels */
2017-12-08 13:00:36 +00:00
if ( s - > mpls )
bgp_encode_mpls_labels ( s , s - > mpls_labels , & pos , & size , pos - 1 ) ;
2017-03-22 14:00:07 +00:00
/* Encode route distinguisher */
put_u64 ( pos , net - > rd ) ;
ADVANCE ( pos , size , 8 ) ;
/* Encode prefix body */
ip6_addr a = ip6_hton ( net - > prefix ) ;
uint b = ( net - > pxlen + 7 ) / 8 ;
memcpy ( pos , & a , b ) ;
ADVANCE ( pos , size , b ) ;
2021-03-29 02:43:04 +00:00
if ( ! s - > sham )
bgp_free_prefix ( s - > channel , px ) ;
else
rem_node ( & px - > buck_node ) ;
2017-03-22 14:00:07 +00:00
}
return pos - buf ;
}
static void
bgp_decode_nlri_vpn6 ( struct bgp_parse_state * s , byte * pos , uint len , rta * a )
{
while ( len )
{
net_addr_vpn6 net ;
u32 path_id = 0 ;
/* Decode path ID */
if ( s - > add_path )
{
if ( len < 5 )
bgp_parse_error ( s , 1 ) ;
path_id = get_u32 ( pos ) ;
ADVANCE ( pos , len , 4 ) ;
}
/* Decode prefix length */
uint l = * pos ;
ADVANCE ( pos , len , 1 ) ;
if ( len < ( ( l + 7 ) / 8 ) )
bgp_parse_error ( s , 1 ) ;
/* Decode MPLS labels */
if ( s - > mpls )
bgp_decode_mpls_labels ( s , & pos , & len , & l , a ) ;
/* Decode route distinguisher */
if ( l < 64 )
bgp_parse_error ( s , 1 ) ;
u64 rd = get_u64 ( pos ) ;
ADVANCE ( pos , len , 8 ) ;
l - = 64 ;
if ( l > IP6_MAX_PREFIX_LENGTH )
bgp_parse_error ( s , 10 ) ;
/* Decode prefix body */
ip6_addr addr = IP6_NONE ;
uint b = ( l + 7 ) / 8 ;
memcpy ( & addr , pos , b ) ;
ADVANCE ( pos , len , b ) ;
net = NET_ADDR_VPN6 ( ip6_ntoh ( addr ) , l , rd ) ;
net_normalize_vpn6 ( & net ) ;
// XXXX validate prefix
bgp_rte_update ( s , ( net_addr * ) & net , path_id , a ) ;
}
}
2016-12-07 17:28:07 +00:00
static uint
bgp_encode_nlri_flow4 ( struct bgp_write_state * s , struct bgp_bucket * buck , byte * buf , uint size )
{
byte * pos = buf ;
while ( ! EMPTY_LIST ( buck - > prefixes ) & & ( size > = 4 ) )
{
struct bgp_prefix * px = HEAD ( buck - > prefixes ) ;
struct net_addr_flow4 * net = ( void * ) px - > net ;
uint flen = net - > length - sizeof ( net_addr_flow4 ) ;
/* Encode path ID */
if ( s - > add_path )
{
put_u32 ( pos , px - > path_id ) ;
ADVANCE ( pos , size , 4 ) ;
}
if ( flen > size )
break ;
/* Copy whole flow data including length */
memcpy ( pos , net - > data , flen ) ;
ADVANCE ( pos , size , flen ) ;
2021-03-29 02:43:04 +00:00
if ( ! s - > sham )
bgp_free_prefix ( s - > channel , px ) ;
else
rem_node ( & px - > buck_node ) ;
2016-12-07 17:28:07 +00:00
}
return pos - buf ;
}
static void
bgp_decode_nlri_flow4 ( struct bgp_parse_state * s , byte * pos , uint len , rta * a )
{
while ( len )
{
u32 path_id = 0 ;
/* Decode path ID */
if ( s - > add_path )
{
if ( len < 4 )
bgp_parse_error ( s , 1 ) ;
path_id = get_u32 ( pos ) ;
ADVANCE ( pos , len , 4 ) ;
}
if ( len < 2 )
bgp_parse_error ( s , 1 ) ;
/* Decode flow length */
uint hlen = flow_hdr_length ( pos ) ;
uint dlen = flow_read_length ( pos ) ;
uint flen = hlen + dlen ;
byte * data = pos + hlen ;
if ( len < flen )
bgp_parse_error ( s , 1 ) ;
/* Validate flow data */
enum flow_validated_state r = flow4_validate ( data , dlen ) ;
if ( r ! = FLOW_ST_VALID )
{
log ( L_REMOTE " %s: Invalid flow route: %s " , s - > proto - > p . name , flow_validated_state_str ( r ) ) ;
bgp_parse_error ( s , 1 ) ;
}
2020-03-03 16:45:16 +00:00
ip4_addr px = IP4_NONE ;
uint pxlen = 0 ;
2016-12-07 17:28:07 +00:00
/* Decode dst prefix */
2020-03-03 16:45:16 +00:00
if ( data [ 0 ] = = FLOW_TYPE_DST_PREFIX )
{
px = flow_read_ip4_part ( data ) ;
pxlen = flow_read_pxlen ( data ) ;
}
2016-12-07 17:28:07 +00:00
/* Prepare the flow */
net_addr * n = alloca ( sizeof ( struct net_addr_flow4 ) + flen ) ;
net_fill_flow4 ( n , px , pxlen , pos , flen ) ;
ADVANCE ( pos , len , flen ) ;
2021-12-20 19:25:35 +00:00
/* Apply validation procedure per RFC 8955 (6) */
if ( a & & s - > channel - > cf - > validate )
bgp_apply_flow_validation ( s , n , a ) ;
2016-12-07 17:28:07 +00:00
bgp_rte_update ( s , n , path_id , a ) ;
}
}
static uint
bgp_encode_nlri_flow6 ( struct bgp_write_state * s , struct bgp_bucket * buck , byte * buf , uint size )
{
byte * pos = buf ;
while ( ! EMPTY_LIST ( buck - > prefixes ) & & ( size > = 4 ) )
{
struct bgp_prefix * px = HEAD ( buck - > prefixes ) ;
struct net_addr_flow6 * net = ( void * ) px - > net ;
uint flen = net - > length - sizeof ( net_addr_flow6 ) ;
/* Encode path ID */
if ( s - > add_path )
{
put_u32 ( pos , px - > path_id ) ;
ADVANCE ( pos , size , 4 ) ;
}
if ( flen > size )
break ;
/* Copy whole flow data including length */
memcpy ( pos , net - > data , flen ) ;
ADVANCE ( pos , size , flen ) ;
2021-03-29 02:43:04 +00:00
if ( ! s - > sham )
bgp_free_prefix ( s - > channel , px ) ;
else
rem_node ( & px - > buck_node ) ;
2016-12-07 17:28:07 +00:00
}
return pos - buf ;
}
static void
bgp_decode_nlri_flow6 ( struct bgp_parse_state * s , byte * pos , uint len , rta * a )
{
while ( len )
{
u32 path_id = 0 ;
/* Decode path ID */
if ( s - > add_path )
{
if ( len < 4 )
bgp_parse_error ( s , 1 ) ;
path_id = get_u32 ( pos ) ;
ADVANCE ( pos , len , 4 ) ;
}
if ( len < 2 )
bgp_parse_error ( s , 1 ) ;
/* Decode flow length */
uint hlen = flow_hdr_length ( pos ) ;
uint dlen = flow_read_length ( pos ) ;
uint flen = hlen + dlen ;
byte * data = pos + hlen ;
if ( len < flen )
bgp_parse_error ( s , 1 ) ;
/* Validate flow data */
enum flow_validated_state r = flow6_validate ( data , dlen ) ;
if ( r ! = FLOW_ST_VALID )
{
log ( L_REMOTE " %s: Invalid flow route: %s " , s - > proto - > p . name , flow_validated_state_str ( r ) ) ;
bgp_parse_error ( s , 1 ) ;
}
2020-03-03 16:45:16 +00:00
ip6_addr px = IP6_NONE ;
uint pxlen = 0 ;
2016-12-07 17:28:07 +00:00
/* Decode dst prefix */
2020-03-03 16:45:16 +00:00
if ( data [ 0 ] = = FLOW_TYPE_DST_PREFIX )
{
px = flow_read_ip6_part ( data ) ;
pxlen = flow_read_pxlen ( data ) ;
}
2016-12-07 17:28:07 +00:00
/* Prepare the flow */
net_addr * n = alloca ( sizeof ( struct net_addr_flow6 ) + flen ) ;
net_fill_flow6 ( n , px , pxlen , pos , flen ) ;
ADVANCE ( pos , len , flen ) ;
2021-12-20 19:25:35 +00:00
/* Apply validation procedure per RFC 8955 (6) */
if ( a & & s - > channel - > cf - > validate )
bgp_apply_flow_validation ( s , n , a ) ;
2016-12-07 17:28:07 +00:00
bgp_rte_update ( s , n , path_id , a ) ;
}
}
2016-12-07 13:11:28 +00:00
static const struct bgp_af_desc bgp_af_table [ ] = {
{
. afi = BGP_AF_IPV4 ,
. net = NET_IP4 ,
. name = " ipv4 " ,
. encode_nlri = bgp_encode_nlri_ip4 ,
. decode_nlri = bgp_decode_nlri_ip4 ,
2017-03-26 17:20:15 +00:00
. encode_next_hop = bgp_encode_next_hop_ip ,
. decode_next_hop = bgp_decode_next_hop_ip ,
2016-12-07 13:11:28 +00:00
. update_next_hop = bgp_update_next_hop_ip ,
} ,
{
. afi = BGP_AF_IPV4_MC ,
. net = NET_IP4 ,
. name = " ipv4-mc " ,
. encode_nlri = bgp_encode_nlri_ip4 ,
. decode_nlri = bgp_decode_nlri_ip4 ,
2017-03-26 17:20:15 +00:00
. encode_next_hop = bgp_encode_next_hop_ip ,
. decode_next_hop = bgp_decode_next_hop_ip ,
2016-12-07 13:11:28 +00:00
. update_next_hop = bgp_update_next_hop_ip ,
} ,
2016-12-07 17:28:07 +00:00
{
2017-03-22 14:00:07 +00:00
. afi = BGP_AF_IPV4_MPLS ,
. net = NET_IP4 ,
. mpls = 1 ,
. name = " ipv4-mpls " ,
. encode_nlri = bgp_encode_nlri_ip4 ,
. decode_nlri = bgp_decode_nlri_ip4 ,
2017-03-26 17:20:15 +00:00
. encode_next_hop = bgp_encode_next_hop_ip ,
. decode_next_hop = bgp_decode_next_hop_ip ,
2017-03-22 14:00:07 +00:00
. update_next_hop = bgp_update_next_hop_ip ,
2016-12-07 17:28:07 +00:00
} ,
2016-12-07 13:11:28 +00:00
{
. afi = BGP_AF_IPV6 ,
. net = NET_IP6 ,
. name = " ipv6 " ,
. encode_nlri = bgp_encode_nlri_ip6 ,
. decode_nlri = bgp_decode_nlri_ip6 ,
2017-03-26 17:20:15 +00:00
. encode_next_hop = bgp_encode_next_hop_ip ,
. decode_next_hop = bgp_decode_next_hop_ip ,
2016-12-07 13:11:28 +00:00
. update_next_hop = bgp_update_next_hop_ip ,
} ,
{
. afi = BGP_AF_IPV6_MC ,
. net = NET_IP6 ,
. name = " ipv6-mc " ,
. encode_nlri = bgp_encode_nlri_ip6 ,
. decode_nlri = bgp_decode_nlri_ip6 ,
2017-03-26 17:20:15 +00:00
. encode_next_hop = bgp_encode_next_hop_ip ,
. decode_next_hop = bgp_decode_next_hop_ip ,
2016-12-07 13:11:28 +00:00
. update_next_hop = bgp_update_next_hop_ip ,
} ,
2017-03-22 14:00:07 +00:00
{
. afi = BGP_AF_IPV6_MPLS ,
. net = NET_IP6 ,
. mpls = 1 ,
. name = " ipv6-mpls " ,
. encode_nlri = bgp_encode_nlri_ip6 ,
. decode_nlri = bgp_decode_nlri_ip6 ,
2017-03-26 17:20:15 +00:00
. encode_next_hop = bgp_encode_next_hop_ip ,
. decode_next_hop = bgp_decode_next_hop_ip ,
2017-03-22 14:00:07 +00:00
. update_next_hop = bgp_update_next_hop_ip ,
} ,
{
. afi = BGP_AF_VPN4_MPLS ,
. net = NET_VPN4 ,
. mpls = 1 ,
. name = " vpn4-mpls " ,
. encode_nlri = bgp_encode_nlri_vpn4 ,
. decode_nlri = bgp_decode_nlri_vpn4 ,
2017-03-26 17:20:15 +00:00
. encode_next_hop = bgp_encode_next_hop_vpn ,
. decode_next_hop = bgp_decode_next_hop_vpn ,
2017-03-22 14:00:07 +00:00
. update_next_hop = bgp_update_next_hop_ip ,
} ,
{
. afi = BGP_AF_VPN6_MPLS ,
. net = NET_VPN6 ,
. mpls = 1 ,
. name = " vpn6-mpls " ,
. encode_nlri = bgp_encode_nlri_vpn6 ,
. decode_nlri = bgp_decode_nlri_vpn6 ,
2017-03-26 17:20:15 +00:00
. encode_next_hop = bgp_encode_next_hop_vpn ,
. decode_next_hop = bgp_decode_next_hop_vpn ,
2017-03-22 14:00:07 +00:00
. update_next_hop = bgp_update_next_hop_ip ,
} ,
2017-03-30 12:00:08 +00:00
{
. afi = BGP_AF_VPN4_MC ,
. net = NET_VPN4 ,
. name = " vpn4-mc " ,
. encode_nlri = bgp_encode_nlri_vpn4 ,
. decode_nlri = bgp_decode_nlri_vpn4 ,
. encode_next_hop = bgp_encode_next_hop_vpn ,
. decode_next_hop = bgp_decode_next_hop_vpn ,
. update_next_hop = bgp_update_next_hop_ip ,
} ,
{
. afi = BGP_AF_VPN6_MC ,
. net = NET_VPN6 ,
. name = " vpn6-mc " ,
. encode_nlri = bgp_encode_nlri_vpn6 ,
. decode_nlri = bgp_decode_nlri_vpn6 ,
. encode_next_hop = bgp_encode_next_hop_vpn ,
. decode_next_hop = bgp_decode_next_hop_vpn ,
. update_next_hop = bgp_update_next_hop_ip ,
} ,
2017-03-22 14:00:07 +00:00
{
. afi = BGP_AF_FLOW4 ,
. net = NET_FLOW4 ,
2017-03-26 17:20:15 +00:00
. no_igp = 1 ,
2017-03-22 14:00:07 +00:00
. name = " flow4 " ,
. encode_nlri = bgp_encode_nlri_flow4 ,
. decode_nlri = bgp_decode_nlri_flow4 ,
. encode_next_hop = bgp_encode_next_hop_none ,
. decode_next_hop = bgp_decode_next_hop_none ,
. update_next_hop = bgp_update_next_hop_none ,
} ,
2016-12-07 17:28:07 +00:00
{
. afi = BGP_AF_FLOW6 ,
. net = NET_FLOW6 ,
2017-03-26 17:20:15 +00:00
. no_igp = 1 ,
2016-12-07 17:28:07 +00:00
. name = " flow6 " ,
. encode_nlri = bgp_encode_nlri_flow6 ,
. decode_nlri = bgp_decode_nlri_flow6 ,
. encode_next_hop = bgp_encode_next_hop_none ,
. decode_next_hop = bgp_decode_next_hop_none ,
. update_next_hop = bgp_update_next_hop_none ,
} ,
2016-12-07 13:11:28 +00:00
} ;
const struct bgp_af_desc *
bgp_get_af_desc ( u32 afi )
2000-03-21 15:53:50 +00:00
{
2016-12-07 13:11:28 +00:00
uint i ;
for ( i = 0 ; i < ARRAY_SIZE ( bgp_af_table ) ; i + + )
if ( bgp_af_table [ i ] . afi = = afi )
return & bgp_af_table [ i ] ;
2000-03-21 15:53:50 +00:00
2016-12-07 13:11:28 +00:00
return NULL ;
2000-03-30 10:44:20 +00:00
}
2016-12-07 13:11:28 +00:00
static inline uint
bgp_encode_nlri ( struct bgp_write_state * s , struct bgp_bucket * buck , byte * buf , byte * end )
{
return s - > channel - > desc - > encode_nlri ( s , buck , buf , end - buf ) ;
}
static inline uint
bgp_encode_next_hop ( struct bgp_write_state * s , eattr * nh , byte * buf )
{
return s - > channel - > desc - > encode_next_hop ( s , nh , buf , 255 ) ;
}
2008-10-26 21:36:08 +00:00
void
2016-12-07 13:11:28 +00:00
bgp_update_next_hop ( struct bgp_export_state * s , eattr * a , ea_list * * to )
2008-10-26 21:36:08 +00:00
{
2016-12-07 13:11:28 +00:00
s - > channel - > desc - > update_next_hop ( s , a , to ) ;
}
2008-10-26 21:36:08 +00:00
2016-12-07 13:11:28 +00:00
# define MAX_ATTRS_LENGTH (end-buf+BGP_HEADER_LENGTH - 1024)
static byte *
bgp_create_ip_reach ( struct bgp_write_state * s , struct bgp_bucket * buck , byte * buf , byte * end )
{
/*
* 2 B Withdrawn Routes Length ( zero )
* - - - IPv4 Withdrawn Routes NLRI ( unused )
* 2 B Total Path Attribute Length
* var Path Attributes
* var IPv4 Network Layer Reachability Information
*/
int lr , la ;
la = bgp_encode_attrs ( s , buck - > eattrs , buf + 4 , buf + MAX_ATTRS_LENGTH ) ;
if ( la < 0 )
{
/* Attribute list too long */
2021-03-29 02:43:04 +00:00
if ( ! s - > sham )
bgp_withdraw_bucket ( s - > channel , buck ) ;
2016-12-07 13:11:28 +00:00
return NULL ;
}
2015-03-29 16:27:13 +00:00
2016-12-07 13:11:28 +00:00
put_u16 ( buf + 0 , 0 ) ;
put_u16 ( buf + 2 , la ) ;
2008-10-26 21:36:08 +00:00
2016-12-07 13:11:28 +00:00
lr = bgp_encode_nlri ( s , buck , buf + 4 + la , end ) ;
2010-01-03 11:17:52 +00:00
2016-12-07 13:11:28 +00:00
return buf + 4 + la + lr ;
}
2015-11-25 14:52:58 +00:00
2016-12-07 13:11:28 +00:00
static byte *
bgp_create_mp_reach ( struct bgp_write_state * s , struct bgp_bucket * buck , byte * buf , byte * end )
{
/*
* 2 B IPv4 Withdrawn Routes Length ( zero )
* - - - IPv4 Withdrawn Routes NLRI ( unused )
* 2 B Total Path Attribute Length
* 1 B MP_REACH_NLRI hdr - Attribute Flags
* 1 B MP_REACH_NLRI hdr - Attribute Type Code
* 2 B MP_REACH_NLRI hdr - Length of Attribute Data
* 2 B MP_REACH_NLRI data - Address Family Identifier
* 1 B MP_REACH_NLRI data - Subsequent Address Family Identifier
* 1 B MP_REACH_NLRI data - Length of Next Hop Network Address
* var MP_REACH_NLRI data - Network Address of Next Hop
* 1 B MP_REACH_NLRI data - Reserved ( zero )
* var MP_REACH_NLRI data - Network Layer Reachability Information
* var Rest of Path Attributes
* - - - IPv4 Network Layer Reachability Information ( unused )
*/
int lh , lr , la ; /* Lengths of next hop, NLRI and attributes */
/* Begin of MP_REACH_NLRI atribute */
buf [ 4 ] = BAF_OPTIONAL | BAF_EXT_LEN ;
buf [ 5 ] = BA_MP_REACH_NLRI ;
put_u16 ( buf + 6 , 0 ) ; /* Will be fixed later */
put_af3 ( buf + 8 , s - > channel - > afi ) ;
byte * pos = buf + 11 ;
/* Encode attributes to temporary buffer */
byte * abuf = alloca ( MAX_ATTRS_LENGTH ) ;
la = bgp_encode_attrs ( s , buck - > eattrs , abuf , abuf + MAX_ATTRS_LENGTH ) ;
if ( la < 0 )
{
/* Attribute list too long */
2021-03-29 02:43:04 +00:00
if ( ! s - > sham )
bgp_withdraw_bucket ( s - > channel , buck ) ;
2016-12-07 13:11:28 +00:00
return NULL ;
}
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
/* Encode the next hop */
lh = bgp_encode_next_hop ( s , s - > mp_next_hop , pos + 1 ) ;
* pos = lh ;
pos + = 1 + lh ;
2008-10-26 21:36:08 +00:00
2016-12-07 13:11:28 +00:00
/* Reserved field */
* pos + + = 0 ;
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
/* Encode the NLRI */
lr = bgp_encode_nlri ( s , buck , pos , end - la ) ;
pos + = lr ;
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
/* End of MP_REACH_NLRI atribute, update data length */
put_u16 ( buf + 6 , pos - buf - 8 ) ;
2008-10-26 21:36:08 +00:00
2016-12-07 13:11:28 +00:00
/* Copy remaining attributes */
memcpy ( pos , abuf , la ) ;
pos + = la ;
/* Initial UPDATE fields */
put_u16 ( buf + 0 , 0 ) ;
put_u16 ( buf + 2 , pos - buf - 4 ) ;
return pos ;
2008-10-26 21:36:08 +00:00
}
2016-12-07 13:11:28 +00:00
# undef MAX_ATTRS_LENGTH
static byte *
bgp_create_ip_unreach ( struct bgp_write_state * s , struct bgp_bucket * buck , byte * buf , byte * end )
2000-04-25 13:32:17 +00:00
{
2016-12-07 13:11:28 +00:00
/*
* 2 B Withdrawn Routes Length
* var IPv4 Withdrawn Routes NLRI
* 2 B Total Path Attribute Length ( zero )
* - - - Path Attributes ( unused )
* - - - IPv4 Network Layer Reachability Information ( unused )
*/
2008-10-26 21:36:08 +00:00
2016-12-07 13:11:28 +00:00
uint len = bgp_encode_nlri ( s , buck , buf + 2 , end ) ;
2008-10-26 21:36:08 +00:00
2016-12-07 13:11:28 +00:00
put_u16 ( buf + 0 , len ) ;
put_u16 ( buf + 2 + len , 0 ) ;
2008-10-26 21:36:08 +00:00
2016-12-07 13:11:28 +00:00
return buf + 4 + len ;
2000-04-25 13:32:17 +00:00
}
2016-12-07 13:11:28 +00:00
static byte *
bgp_create_mp_unreach ( struct bgp_write_state * s , struct bgp_bucket * buck , byte * buf , byte * end )
2000-03-30 10:44:20 +00:00
{
2016-12-07 13:11:28 +00:00
/*
* 2 B Withdrawn Routes Length ( zero )
* - - - IPv4 Withdrawn Routes NLRI ( unused )
* 2 B Total Path Attribute Length
* 1 B MP_UNREACH_NLRI hdr - Attribute Flags
* 1 B MP_UNREACH_NLRI hdr - Attribute Type Code
* 2 B MP_UNREACH_NLRI hdr - Length of Attribute Data
* 2 B MP_UNREACH_NLRI data - Address Family Identifier
* 1 B MP_UNREACH_NLRI data - Subsequent Address Family Identifier
* var MP_UNREACH_NLRI data - Network Layer Reachability Information
* - - - IPv4 Network Layer Reachability Information ( unused )
*/
uint len = bgp_encode_nlri ( s , buck , buf + 11 , end ) ;
2000-03-30 10:44:20 +00:00
2016-12-07 13:11:28 +00:00
put_u16 ( buf + 0 , 0 ) ;
put_u16 ( buf + 2 , 7 + len ) ;
2000-03-30 10:44:20 +00:00
2016-12-07 13:11:28 +00:00
/* Begin of MP_UNREACH_NLRI atribute */
buf [ 4 ] = BAF_OPTIONAL | BAF_EXT_LEN ;
buf [ 5 ] = BA_MP_UNREACH_NLRI ;
put_u16 ( buf + 6 , 3 + len ) ;
put_af3 ( buf + 8 , s - > channel - > afi ) ;
2008-10-26 21:36:08 +00:00
2016-12-07 13:11:28 +00:00
return buf + 11 + len ;
}
2008-10-26 21:36:08 +00:00
2023-04-18 15:21:13 +00:00
# ifdef CONFIG_BMP
2021-03-29 20:45:21 +00:00
static byte *
2021-03-29 02:43:04 +00:00
bgp_create_update_bmp ( struct bgp_channel * c , byte * buf , struct bgp_bucket * buck , bool update )
2021-03-29 20:45:21 +00:00
{
2021-03-29 02:43:04 +00:00
struct bgp_proto * p = ( void * ) c - > c . proto ;
byte * end = buf + ( BGP_MAX_EXT_MSG_LENGTH - BGP_HEADER_LENGTH ) ;
2023-05-30 13:37:52 +00:00
byte * res = NULL ;
2021-03-29 02:43:04 +00:00
/* FIXME: must be a bit shorter */
2021-03-29 20:45:21 +00:00
2023-05-30 13:37:52 +00:00
struct lp_state tmpp ;
lp_save ( tmp_linpool , & tmpp ) ;
2021-03-29 20:45:21 +00:00
struct bgp_caps * peer = p - > conn - > remote_caps ;
const struct bgp_af_caps * rem = bgp_find_af_caps ( peer , c - > afi ) ;
2023-05-30 13:37:52 +00:00
2021-03-29 20:45:21 +00:00
struct bgp_write_state s = {
. proto = p ,
. channel = c ,
. pool = tmp_linpool ,
2023-05-30 13:37:52 +00:00
. mp_reach = ( c - > afi ! = BGP_AF_IPV4 ) | | ( rem & & rem - > ext_next_hop ) ,
2021-03-29 02:43:04 +00:00
. as4_session = 1 ,
2021-03-29 20:45:21 +00:00
. add_path = c - > add_path_rx ,
. mpls = c - > desc - > mpls ,
2021-03-29 02:43:04 +00:00
. sham = 1 ,
2021-03-29 20:45:21 +00:00
} ;
2021-03-29 02:43:04 +00:00
if ( ! update )
2021-03-29 20:45:21 +00:00
{
2023-05-30 13:37:52 +00:00
res = ! s . mp_reach ?
2021-03-29 02:43:04 +00:00
bgp_create_ip_unreach ( & s , buck , buf , end ) :
bgp_create_mp_unreach ( & s , buck , buf , end ) ;
2021-03-29 20:45:21 +00:00
}
2021-03-29 02:43:04 +00:00
else
2021-03-29 20:45:21 +00:00
{
2023-05-30 13:37:52 +00:00
res = ! s . mp_reach ?
2021-03-29 02:43:04 +00:00
bgp_create_ip_reach ( & s , buck , buf , end ) :
bgp_create_mp_reach ( & s , buck , buf , end ) ;
2021-03-29 20:45:21 +00:00
}
2023-05-30 13:37:52 +00:00
lp_restore ( tmp_linpool , & tmpp ) ;
return res ;
2021-03-29 02:43:04 +00:00
}
2021-03-29 20:45:21 +00:00
2021-03-29 02:43:04 +00:00
static byte *
bgp_bmp_prepare_bgp_hdr ( byte * buf , const u16 msg_size , const u8 msg_type )
{
memset ( buf + BGP_MSG_HDR_MARKER_POS , 0xff , BGP_MSG_HDR_MARKER_SIZE ) ;
put_u16 ( buf + BGP_MSG_HDR_LENGTH_POS , msg_size ) ;
put_u8 ( buf + BGP_MSG_HDR_TYPE_POS , msg_type ) ;
2021-03-29 20:45:21 +00:00
2021-03-29 02:43:04 +00:00
return buf + BGP_MSG_HDR_TYPE_POS + BGP_MSG_HDR_TYPE_SIZE ;
}
2023-08-01 15:56:56 +00:00
byte *
bgp_bmp_encode_rte ( struct bgp_channel * c , byte * buf , const net_addr * n ,
2023-06-08 02:56:41 +00:00
const struct rte * new , const struct rte_src * src )
2021-03-29 02:43:04 +00:00
{
2023-06-08 02:56:41 +00:00
// struct bgp_proto *p = (void *) c->c.proto;
2021-03-29 02:43:04 +00:00
byte * pkt = buf + BGP_HEADER_LENGTH ;
ea_list * attrs = new ? new - > attrs - > eattrs : NULL ;
uint ea_size = new ? ( sizeof ( ea_list ) + attrs - > count * sizeof ( eattr ) ) : 0 ;
uint bucket_size = sizeof ( struct bgp_bucket ) + ea_size ;
uint prefix_size = sizeof ( struct bgp_prefix ) + n - > length ;
/* Sham bucket */
struct bgp_bucket * b = alloca ( bucket_size ) ;
* b = ( struct bgp_bucket ) { } ;
init_list ( & b - > prefixes ) ;
if ( attrs )
memcpy ( b - > eattrs , attrs , ea_size ) ;
/* Sham prefix */
struct bgp_prefix * px = alloca ( prefix_size ) ;
* px = ( struct bgp_prefix ) { } ;
2023-10-02 13:09:30 +00:00
px - > path_id = ( u32 ) src - > private_id ;
2021-03-29 02:43:04 +00:00
net_copy ( px - > net , n ) ;
add_tail ( & b - > prefixes , & px - > buck_node ) ;
byte * end = bgp_create_update_bmp ( c , pkt , b , ! ! new ) ;
2023-08-01 15:56:56 +00:00
if ( end )
bgp_bmp_prepare_bgp_hdr ( buf , end - buf , PKT_UPDATE ) ;
return end ;
2021-03-29 20:45:21 +00:00
}
2023-04-18 15:21:13 +00:00
# endif /* CONFIG_BMP */
2016-12-07 13:11:28 +00:00
static byte *
bgp_create_update ( struct bgp_channel * c , byte * buf )
{
struct bgp_proto * p = ( void * ) c - > c . proto ;
struct bgp_bucket * buck ;
byte * end = buf + ( bgp_max_packet_length ( p - > conn ) - BGP_HEADER_LENGTH ) ;
byte * res = NULL ;
2017-03-22 14:00:07 +00:00
again : ;
2022-04-05 13:09:56 +00:00
struct lp_state tmpp ;
lp_save ( tmp_linpool , & tmpp ) ;
2016-12-07 13:11:28 +00:00
/* Initialize write state */
struct bgp_write_state s = {
. proto = p ,
. channel = c ,
2022-03-02 10:22:32 +00:00
. pool = tmp_linpool ,
2018-11-20 16:38:19 +00:00
. mp_reach = ( c - > afi ! = BGP_AF_IPV4 ) | | c - > ext_next_hop ,
2016-12-07 13:11:28 +00:00
. as4_session = p - > as4_session ,
. add_path = c - > add_path_tx ,
2017-03-22 14:00:07 +00:00
. mpls = c - > desc - > mpls ,
2016-12-07 13:11:28 +00:00
} ;
/* Try unreachable bucket */
if ( ( buck = c - > withdraw_bucket ) & & ! EMPTY_LIST ( buck - > prefixes ) )
{
2017-03-26 17:20:15 +00:00
res = ( c - > afi = = BGP_AF_IPV4 ) & & ! c - > ext_next_hop ?
2016-12-07 13:11:28 +00:00
bgp_create_ip_unreach ( & s , buck , buf , end ) :
bgp_create_mp_unreach ( & s , buck , buf , end ) ;
2008-10-26 21:36:08 +00:00
2016-12-07 13:11:28 +00:00
goto done ;
}
2000-03-30 10:44:20 +00:00
2016-12-07 13:11:28 +00:00
/* Try reachable buckets */
if ( ! EMPTY_LIST ( c - > bucket_queue ) )
{
buck = HEAD ( c - > bucket_queue ) ;
2009-03-13 11:49:44 +00:00
2016-12-07 13:11:28 +00:00
/* Cleanup empty buckets */
if ( EMPTY_LIST ( buck - > prefixes ) )
2009-09-24 21:14:44 +00:00
{
2016-12-07 13:11:28 +00:00
bgp_free_bucket ( c , buck ) ;
2022-04-05 13:09:56 +00:00
lp_restore ( tmp_linpool , & tmpp ) ;
2016-12-07 13:11:28 +00:00
goto again ;
2009-09-24 21:14:44 +00:00
}
2008-10-26 21:36:08 +00:00
2018-11-20 16:38:19 +00:00
res = ! s . mp_reach ?
2016-12-07 13:11:28 +00:00
bgp_create_ip_reach ( & s , buck , buf , end ) :
bgp_create_mp_reach ( & s , buck , buf , end ) ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
if ( EMPTY_LIST ( buck - > prefixes ) )
bgp_free_bucket ( c , buck ) ;
else
bgp_defer_bucket ( c , buck ) ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
if ( ! res )
2022-04-05 13:09:56 +00:00
{
lp_restore ( tmp_linpool , & tmpp ) ;
2016-12-07 13:11:28 +00:00
goto again ;
2022-04-05 13:09:56 +00:00
}
2000-03-30 17:39:48 +00:00
2016-12-07 13:11:28 +00:00
goto done ;
}
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
/* No more prefixes to send */
return NULL ;
2008-12-24 16:24:41 +00:00
2016-12-07 13:11:28 +00:00
done :
BGP_TRACE_RL ( & rl_snd_update , D_PACKETS , " Sending UPDATE " ) ;
2019-12-03 17:05:41 +00:00
p - > stats . tx_updates + + ;
2022-04-05 13:09:56 +00:00
lp_restore ( tmp_linpool , & tmpp ) ;
2000-03-30 10:44:20 +00:00
2016-12-07 13:11:28 +00:00
return res ;
2000-03-30 10:44:20 +00:00
}
2016-12-07 13:11:28 +00:00
static byte *
bgp_create_ip_end_mark ( struct bgp_channel * c UNUSED , byte * buf )
{
/* Empty update packet */
put_u32 ( buf , 0 ) ;
return buf + 4 ;
}
static byte *
bgp_create_mp_end_mark ( struct bgp_channel * c , byte * buf )
{
put_u16 ( buf + 0 , 0 ) ;
put_u16 ( buf + 2 , 6 ) ; /* length 4--9 */
/* Empty MP_UNREACH_NLRI atribute */
buf [ 4 ] = BAF_OPTIONAL ;
buf [ 5 ] = BA_MP_UNREACH_NLRI ;
buf [ 6 ] = 3 ; /* Length 7--9 */
put_af3 ( buf + 7 , c - > afi ) ;
return buf + 10 ;
}
2021-03-29 20:45:21 +00:00
byte *
2023-06-08 02:56:41 +00:00
bgp_create_end_mark_ ( struct bgp_channel * c , byte * buf )
{
return ( c - > afi = = BGP_AF_IPV4 ) ?
bgp_create_ip_end_mark ( c , buf ) :
bgp_create_mp_end_mark ( c , buf ) ;
}
static byte *
2016-12-07 13:11:28 +00:00
bgp_create_end_mark ( struct bgp_channel * c , byte * buf )
{
struct bgp_proto * p = ( void * ) c - > c . proto ;
BGP_TRACE ( D_PACKETS , " Sending END-OF-RIB " ) ;
2019-12-03 17:05:41 +00:00
p - > stats . tx_updates + + ;
2016-12-07 13:11:28 +00:00
2023-06-08 02:56:41 +00:00
return bgp_create_end_mark_ ( c , buf ) ;
2016-12-07 13:11:28 +00:00
}
2014-03-20 13:07:12 +00:00
static inline void
2017-02-07 14:55:51 +00:00
bgp_rx_end_mark ( struct bgp_parse_state * s , u32 afi )
2014-03-20 13:07:12 +00:00
{
2017-02-07 14:55:51 +00:00
struct bgp_proto * p = s - > proto ;
2016-12-07 13:11:28 +00:00
struct bgp_channel * c = bgp_get_channel ( p , afi ) ;
2015-03-29 16:27:13 +00:00
BGP_TRACE ( D_PACKETS , " Got END-OF-RIB " ) ;
2016-12-07 13:11:28 +00:00
if ( ! c )
2017-02-07 14:55:51 +00:00
DISCARD ( BAD_AFI , BGP_AFI ( afi ) , BGP_SAFI ( afi ) ) ;
2016-12-07 13:11:28 +00:00
if ( c - > load_state = = BFS_LOADING )
c - > load_state = BFS_NONE ;
2014-03-20 13:07:12 +00:00
if ( p - > p . gr_recovery )
2016-12-07 13:11:28 +00:00
channel_graceful_restart_unlock ( & c - > c ) ;
if ( c - > gr_active )
bgp_graceful_restart_done ( c ) ;
}
static inline void
bgp_decode_nlri ( struct bgp_parse_state * s , u32 afi , byte * nlri , uint len , ea_list * ea , byte * nh , uint nh_len )
{
struct bgp_channel * c = bgp_get_channel ( s - > proto , afi ) ;
rta * a = NULL ;
if ( ! c )
2017-02-07 14:55:51 +00:00
DISCARD ( BAD_AFI , BGP_AFI ( afi ) , BGP_SAFI ( afi ) ) ;
2016-12-07 13:11:28 +00:00
s - > channel = c ;
s - > add_path = c - > add_path_rx ;
2017-03-22 14:00:07 +00:00
s - > mpls = c - > desc - > mpls ;
2016-12-07 13:11:28 +00:00
s - > last_id = 0 ;
s - > last_src = s - > proto - > p . main_source ;
/*
* IPv4 BGP and MP - BGP may be used together in one update , therefore we do not
* add BA_NEXT_HOP in bgp_decode_attrs ( ) , but we add it here independently for
* IPv4 BGP and MP - BGP . We undo the attribute ( and possibly others attached by
* decode_next_hop hooks ) by restoring a - > eattrs afterwards .
*/
if ( ea )
{
2017-02-24 13:05:11 +00:00
a = allocz ( RTA_MAX_SIZE ) ;
2016-12-07 13:11:28 +00:00
a - > source = RTS_BGP ;
a - > scope = SCOPE_UNIVERSE ;
2019-04-02 15:22:31 +00:00
a - > from = s - > proto - > remote_ip ;
2016-12-07 13:11:28 +00:00
a - > eattrs = ea ;
2020-02-10 07:41:05 +00:00
a - > pref = c - > c . preference ;
2016-12-07 13:11:28 +00:00
c - > desc - > decode_next_hop ( s , nh , nh_len , a ) ;
2019-09-28 12:17:20 +00:00
bgp_finish_attrs ( s , a ) ;
2016-12-07 13:11:28 +00:00
/* Handle withdraw during next hop decoding */
if ( s - > err_withdraw )
a = NULL ;
}
c - > desc - > decode_nlri ( s , nlri , len , a ) ;
rta_free ( s - > cached_rta ) ;
s - > cached_rta = NULL ;
}
static void
bgp_rx_update ( struct bgp_conn * conn , byte * pkt , uint len )
{
struct bgp_proto * p = conn - > bgp ;
ea_list * ea = NULL ;
BGP_TRACE_RL ( & rl_rcv_update , D_PACKETS , " Got UPDATE " ) ;
2019-12-03 17:05:41 +00:00
p - > last_rx_update = current_time ( ) ;
p - > stats . rx_updates + + ;
2016-12-07 13:11:28 +00:00
/* Workaround for some BGP implementations that skip initial KEEPALIVE */
if ( conn - > state = = BS_OPENCONFIRM )
bgp_conn_enter_established_state ( conn ) ;
if ( conn - > state ! = BS_ESTABLISHED )
{ bgp_error ( conn , 5 , fsm_err_subcode [ conn - > state ] , NULL , 0 ) ; return ; }
bgp_start_timer ( conn - > hold_timer , conn - > hold_time ) ;
2022-04-05 13:09:56 +00:00
struct lp_state tmpp ;
lp_save ( tmp_linpool , & tmpp ) ;
2016-12-07 13:11:28 +00:00
/* Initialize parse state */
struct bgp_parse_state s = {
. proto = p ,
2022-03-02 10:22:32 +00:00
. pool = tmp_linpool ,
2016-12-07 13:11:28 +00:00
. as4_session = p - > as4_session ,
} ;
/* Parse error handler */
if ( setjmp ( s . err_jmpbuf ) )
{
bgp_error ( conn , 3 , s . err_subcode , NULL , 0 ) ;
goto done ;
}
/* Check minimal length */
if ( len < 23 )
{ bgp_error ( conn , 1 , 2 , pkt + 16 , 2 ) ; return ; }
/* Skip fixed header */
uint pos = 19 ;
/*
* UPDATE message format
*
* 2 B IPv4 Withdrawn Routes Length
* var IPv4 Withdrawn Routes NLRI
* 2 B Total Path Attribute Length
* var Path Attributes
* var IPv4 Reachable Routes NLRI
*/
s . ip_unreach_len = get_u16 ( pkt + pos ) ;
s . ip_unreach_nlri = pkt + pos + 2 ;
pos + = 2 + s . ip_unreach_len ;
if ( pos + 2 > len )
bgp_parse_error ( & s , 1 ) ;
s . attr_len = get_u16 ( pkt + pos ) ;
s . attrs = pkt + pos + 2 ;
pos + = 2 + s . attr_len ;
if ( pos > len )
bgp_parse_error ( & s , 1 ) ;
s . ip_reach_len = len - pos ;
s . ip_reach_nlri = pkt + pos ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
if ( s . attr_len )
ea = bgp_decode_attrs ( & s , s . attrs , s . attr_len ) ;
2018-01-02 15:57:45 +00:00
else
ea = NULL ;
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
/* Check for End-of-RIB marker */
if ( ! s . attr_len & & ! s . ip_unreach_len & & ! s . ip_reach_len )
2017-02-07 14:55:51 +00:00
{ bgp_rx_end_mark ( & s , BGP_AF_IPV4 ) ; goto done ; }
2000-03-30 18:44:23 +00:00
2016-12-07 13:11:28 +00:00
/* Check for MP End-of-RIB marker */
if ( ( s . attr_len < 8 ) & & ! s . ip_unreach_len & & ! s . ip_reach_len & &
2017-02-07 14:55:51 +00:00
! s . mp_reach_len & & ! s . mp_unreach_len & & s . mp_unreach_af )
{ bgp_rx_end_mark ( & s , s . mp_unreach_af ) ; goto done ; }
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
if ( s . ip_unreach_len )
bgp_decode_nlri ( & s , BGP_AF_IPV4 , s . ip_unreach_nlri , s . ip_unreach_len , NULL , NULL , 0 ) ;
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
if ( s . mp_unreach_len )
bgp_decode_nlri ( & s , s . mp_unreach_af , s . mp_unreach_nlri , s . mp_unreach_len , NULL , NULL , 0 ) ;
2012-08-14 14:25:22 +00:00
2022-01-24 02:44:21 +00:00
s . reach_nlri_step = 1 ;
2016-12-07 13:11:28 +00:00
if ( s . ip_reach_len )
bgp_decode_nlri ( & s , BGP_AF_IPV4 , s . ip_reach_nlri , s . ip_reach_len ,
ea , s . ip_next_hop_data , s . ip_next_hop_len ) ;
2015-03-02 09:58:20 +00:00
2016-12-07 13:11:28 +00:00
if ( s . mp_reach_len )
bgp_decode_nlri ( & s , s . mp_reach_af , s . mp_reach_nlri , s . mp_reach_len ,
ea , s . mp_next_hop_data , s . mp_next_hop_len ) ;
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
done :
rta_free ( s . cached_rta ) ;
2022-04-05 13:09:56 +00:00
lp_restore ( tmp_linpool , & tmpp ) ;
2016-12-07 13:11:28 +00:00
return ;
2012-08-14 14:25:22 +00:00
}
2018-11-20 16:38:19 +00:00
static uint
bgp_find_update_afi ( byte * pos , uint len )
{
/*
* This is stripped - down version of bgp_rx_update ( ) , bgp_decode_attrs ( ) and
* bgp_decode_mp_ [ un ] reach_nlri ( ) used by MRT code in order to find out which
* AFI / SAFI is associated with incoming UPDATE . Returns 0 for framing errors .
*/
if ( len < 23 )
return 0 ;
/* Assume there is no withrawn NLRI, read lengths and move to attribute list */
uint wlen = get_u16 ( pos + 19 ) ;
uint alen = get_u16 ( pos + 21 ) ;
ADVANCE ( pos , len , 23 ) ;
/* Either non-zero withdrawn NLRI, non-zero reachable NLRI, or IPv4 End-of-RIB */
if ( ( wlen ! = 0 ) | | ( alen < len ) | | ! alen )
return BGP_AF_IPV4 ;
if ( alen > len )
return 0 ;
/* Process attribute list (alen == len) */
while ( len )
{
if ( len < 2 )
return 0 ;
uint flags = pos [ 0 ] ;
uint code = pos [ 1 ] ;
ADVANCE ( pos , len , 2 ) ;
uint ll = ! ( flags & BAF_EXT_LEN ) ? 1 : 2 ;
if ( len < ll )
return 0 ;
/* Read attribute length and move to attribute body */
alen = ( ll = = 1 ) ? get_u8 ( pos ) : get_u16 ( pos ) ;
ADVANCE ( pos , len , ll ) ;
if ( len < alen )
return 0 ;
/* Found MP NLRI */
if ( ( code = = BA_MP_REACH_NLRI ) | | ( code = = BA_MP_UNREACH_NLRI ) )
{
if ( alen < 3 )
return 0 ;
return BGP_AF ( get_u16 ( pos ) , pos [ 2 ] ) ;
}
/* Move to the next attribute */
ADVANCE ( pos , len , alen ) ;
}
/* No basic or MP NLRI, but there are some attributes -> error */
return 0 ;
}
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
/*
* ROUTE - REFRESH
*/
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
static inline byte *
bgp_create_route_refresh ( struct bgp_channel * c , byte * buf )
2000-05-04 09:03:31 +00:00
{
2016-12-07 13:11:28 +00:00
struct bgp_proto * p = ( void * ) c - > c . proto ;
2010-07-28 09:45:35 +00:00
2016-12-07 13:11:28 +00:00
BGP_TRACE ( D_PACKETS , " Sending ROUTE-REFRESH " ) ;
2012-01-08 14:28:27 +00:00
2016-12-07 13:11:28 +00:00
/* Original route refresh request, RFC 2918 */
put_af4 ( buf , c - > afi ) ;
buf [ 2 ] = BGP_RR_REQUEST ;
2010-07-05 15:50:19 +00:00
2016-12-07 13:11:28 +00:00
return buf + 4 ;
}
2012-01-08 14:28:27 +00:00
2016-12-07 13:11:28 +00:00
static inline byte *
bgp_create_begin_refresh ( struct bgp_channel * c , byte * buf )
{
struct bgp_proto * p = ( void * ) c - > c . proto ;
2012-01-08 14:28:27 +00:00
2016-12-07 13:11:28 +00:00
BGP_TRACE ( D_PACKETS , " Sending BEGIN-OF-RR " ) ;
2012-01-08 14:28:27 +00:00
2016-12-07 13:11:28 +00:00
/* Demarcation of beginning of route refresh (BoRR), RFC 7313 */
put_af4 ( buf , c - > afi ) ;
buf [ 2 ] = BGP_RR_BEGIN ;
2010-07-05 15:50:19 +00:00
2016-12-07 13:11:28 +00:00
return buf + 4 ;
}
2012-01-08 14:28:27 +00:00
2016-12-07 13:11:28 +00:00
static inline byte *
bgp_create_end_refresh ( struct bgp_channel * c , byte * buf )
{
struct bgp_proto * p = ( void * ) c - > c . proto ;
2010-07-05 15:50:19 +00:00
2016-12-07 13:11:28 +00:00
BGP_TRACE ( D_PACKETS , " Sending END-OF-RR " ) ;
/* Demarcation of ending of route refresh (EoRR), RFC 7313 */
put_af4 ( buf , c - > afi ) ;
buf [ 2 ] = BGP_RR_END ;
2000-05-04 09:03:31 +00:00
2016-12-07 13:11:28 +00:00
return buf + 4 ;
}
2000-05-04 09:03:31 +00:00
2000-03-30 10:44:20 +00:00
static void
2016-12-07 13:11:28 +00:00
bgp_rx_route_refresh ( struct bgp_conn * conn , byte * pkt , uint len )
2000-03-30 10:44:20 +00:00
{
2000-05-02 16:07:41 +00:00
struct bgp_proto * p = conn - > bgp ;
2000-03-30 18:44:23 +00:00
2016-12-07 13:11:28 +00:00
if ( conn - > state ! = BS_ESTABLISHED )
{ bgp_error ( conn , 5 , fsm_err_subcode [ conn - > state ] , NULL , 0 ) ; return ; }
2014-03-20 13:07:12 +00:00
2016-12-07 13:11:28 +00:00
if ( ! conn - > local_caps - > route_refresh )
{ bgp_error ( conn , 1 , 3 , pkt + 18 , 1 ) ; return ; }
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
if ( len < ( BGP_HEADER_LENGTH + 4 ) )
{ bgp_error ( conn , 1 , 2 , pkt + 16 , 2 ) ; return ; }
if ( len > ( BGP_HEADER_LENGTH + 4 ) )
{ bgp_error ( conn , 7 , 1 , pkt , MIN ( len , 2048 ) ) ; return ; }
2000-03-30 18:44:23 +00:00
2016-12-07 13:11:28 +00:00
struct bgp_channel * c = bgp_get_channel ( p , get_af4 ( pkt + 19 ) ) ;
if ( ! c )
{
log ( L_WARN " %s: Got ROUTE-REFRESH subtype %u for AF %u.%u, ignoring " ,
p - > p . name , pkt [ 21 ] , get_u16 ( pkt + 19 ) , pkt [ 22 ] ) ;
2000-04-27 22:40:19 +00:00
return ;
2016-12-07 13:11:28 +00:00
}
2000-04-27 22:40:19 +00:00
2016-12-07 13:11:28 +00:00
/* RFC 7313 redefined reserved field as RR message subtype */
uint subtype = p - > enhanced_refresh ? pkt [ 21 ] : BGP_RR_REQUEST ;
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
switch ( subtype )
{
case BGP_RR_REQUEST :
BGP_TRACE ( D_PACKETS , " Got ROUTE-REFRESH " ) ;
channel_request_feeding ( & c - > c ) ;
break ;
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
case BGP_RR_BEGIN :
BGP_TRACE ( D_PACKETS , " Got BEGIN-OF-RR " ) ;
bgp_refresh_begin ( c ) ;
break ;
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
case BGP_RR_END :
BGP_TRACE ( D_PACKETS , " Got END-OF-RR " ) ;
bgp_refresh_end ( c ) ;
break ;
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
default :
log ( L_WARN " %s: Got ROUTE-REFRESH message with unknown subtype %u, ignoring " ,
p - > p . name , subtype ) ;
break ;
}
}
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
static inline struct bgp_channel *
bgp_get_channel_to_send ( struct bgp_proto * p , struct bgp_conn * conn )
{
uint i = conn - > last_channel ;
2009-06-04 11:31:09 +00:00
2016-12-07 13:11:28 +00:00
/* Try the last channel, but at most several times */
if ( ( conn - > channels_to_send & ( 1 < < i ) ) & &
( conn - > last_channel_count < 16 ) )
goto found ;
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
/* Find channel with non-zero channels_to_send */
do
{
i + + ;
if ( i > = p - > channel_count )
i = 0 ;
}
while ( ! ( conn - > channels_to_send & ( 1 < < i ) ) ) ;
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
/* Use that channel */
conn - > last_channel = i ;
conn - > last_channel_count = 0 ;
2000-04-01 09:17:33 +00:00
2016-12-07 13:11:28 +00:00
found :
conn - > last_channel_count + + ;
return p - > channel_map [ i ] ;
}
2000-05-04 09:03:31 +00:00
2016-12-07 13:11:28 +00:00
static inline int
bgp_send ( struct bgp_conn * conn , uint type , uint len )
2011-03-29 23:09:18 +00:00
{
2016-12-07 13:11:28 +00:00
sock * sk = conn - > sk ;
byte * buf = sk - > tbuf ;
2011-03-29 23:09:18 +00:00
2019-12-03 17:05:41 +00:00
conn - > bgp - > stats . tx_messages + + ;
conn - > bgp - > stats . tx_bytes + = len ;
2023-04-28 17:13:56 +00:00
memset ( buf , 0xff , BGP_HDR_MARKER_LENGTH ) ;
2016-12-07 13:11:28 +00:00
put_u16 ( buf + 16 , len ) ;
buf [ 18 ] = type ;
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
return sk_send ( sk , len ) ;
}
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
/**
* bgp_fire_tx - transmit packets
* @ conn : connection
*
* Whenever the transmit buffers of the underlying TCP connection
* are free and we have any packets queued for sending , the socket functions
* call bgp_fire_tx ( ) which takes care of selecting the highest priority packet
* queued ( Notification > Keepalive > Open > Update ) , assembling its header
* and body and sending it to the connection .
*/
static int
bgp_fire_tx ( struct bgp_conn * conn )
2000-05-04 09:03:31 +00:00
{
struct bgp_proto * p = conn - > bgp ;
2016-12-07 13:11:28 +00:00
struct bgp_channel * c ;
byte * buf , * pkt , * end ;
uint s ;
2000-05-04 09:03:31 +00:00
2016-12-07 13:11:28 +00:00
if ( ! conn - > sk )
return 0 ;
buf = conn - > sk - > tbuf ;
pkt = buf + BGP_HEADER_LENGTH ;
s = conn - > packets_to_send ;
if ( s & ( 1 < < PKT_SCHEDULE_CLOSE ) )
{
/* We can finally close connection and enter idle state */
bgp_conn_enter_idle_state ( conn ) ;
return 0 ;
}
if ( s & ( 1 < < PKT_NOTIFICATION ) )
{
conn - > packets_to_send = 1 < < PKT_SCHEDULE_CLOSE ;
end = bgp_create_notification ( conn , pkt ) ;
return bgp_send ( conn , PKT_NOTIFICATION , end - buf ) ;
}
2019-04-08 14:39:22 +00:00
else if ( s & ( 1 < < PKT_OPEN ) )
{
conn - > packets_to_send & = ~ ( 1 < < PKT_OPEN ) ;
end = bgp_create_open ( conn , pkt ) ;
2023-04-28 17:13:56 +00:00
conn - > local_open_msg = bgp_copy_open ( p , buf , end - buf ) ;
conn - > local_open_length = end - buf - BGP_HEADER_LENGTH ;
2023-05-01 01:35:21 +00:00
return bgp_send ( conn , PKT_OPEN , end - buf ) ;
2019-04-08 14:39:22 +00:00
}
2016-12-07 13:11:28 +00:00
else if ( s & ( 1 < < PKT_KEEPALIVE ) )
{
conn - > packets_to_send & = ~ ( 1 < < PKT_KEEPALIVE ) ;
BGP_TRACE ( D_PACKETS , " Sending KEEPALIVE " ) ;
bgp_start_timer ( conn - > keepalive_timer , conn - > keepalive_time ) ;
return bgp_send ( conn , PKT_KEEPALIVE , BGP_HEADER_LENGTH ) ;
}
else while ( conn - > channels_to_send )
{
c = bgp_get_channel_to_send ( p , conn ) ;
s = c - > packets_to_send ;
if ( s & ( 1 < < PKT_ROUTE_REFRESH ) )
2014-03-20 13:07:12 +00:00
{
2016-12-07 13:11:28 +00:00
c - > packets_to_send & = ~ ( 1 < < PKT_ROUTE_REFRESH ) ;
end = bgp_create_route_refresh ( c , pkt ) ;
return bgp_send ( conn , PKT_ROUTE_REFRESH , end - buf ) ;
2014-03-20 13:07:12 +00:00
}
2016-12-07 13:11:28 +00:00
else if ( s & ( 1 < < PKT_BEGIN_REFRESH ) )
2000-05-04 09:03:31 +00:00
{
2016-12-07 13:11:28 +00:00
/* BoRR is a subtype of RR, but uses separate bit in packets_to_send */
c - > packets_to_send & = ~ ( 1 < < PKT_BEGIN_REFRESH ) ;
end = bgp_create_begin_refresh ( c , pkt ) ;
return bgp_send ( conn , PKT_ROUTE_REFRESH , end - buf ) ;
2000-05-04 09:03:31 +00:00
}
2016-12-07 13:11:28 +00:00
else if ( s & ( 1 < < PKT_UPDATE ) )
2000-05-04 09:03:31 +00:00
{
2016-12-07 13:11:28 +00:00
end = bgp_create_update ( c , pkt ) ;
if ( end )
return bgp_send ( conn , PKT_UPDATE , end - buf ) ;
2000-05-04 09:03:31 +00:00
2016-12-07 13:11:28 +00:00
/* No update to send, perhaps we need to send End-of-RIB or EoRR */
c - > packets_to_send = 0 ;
conn - > channels_to_send & = ~ ( 1 < < c - > index ) ;
2009-04-23 21:15:07 +00:00
2016-12-07 13:11:28 +00:00
if ( c - > feed_state = = BFS_LOADED )
{
c - > feed_state = BFS_NONE ;
end = bgp_create_end_mark ( c , pkt ) ;
return bgp_send ( conn , PKT_UPDATE , end - buf ) ;
}
2000-05-04 09:03:31 +00:00
2016-12-07 13:11:28 +00:00
else if ( c - > feed_state = = BFS_REFRESHED )
{
c - > feed_state = BFS_NONE ;
end = bgp_create_end_refresh ( c , pkt ) ;
return bgp_send ( conn , PKT_ROUTE_REFRESH , end - buf ) ;
}
}
else if ( s )
bug ( " Channel packets_to_send: %x " , s ) ;
2012-08-14 14:25:22 +00:00
2016-12-07 13:11:28 +00:00
c - > packets_to_send = 0 ;
conn - > channels_to_send & = ~ ( 1 < < c - > index ) ;
}
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
return 0 ;
}
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
/**
* bgp_schedule_packet - schedule a packet for transmission
* @ conn : connection
* @ c : channel
* @ type : packet type
*
* Schedule a packet of type @ type to be sent as soon as possible .
*/
void
bgp_schedule_packet ( struct bgp_conn * conn , struct bgp_channel * c , int type )
{
ASSERT ( conn - > sk ) ;
2000-05-04 09:03:31 +00:00
2016-12-07 13:11:28 +00:00
DBG ( " BGP: Scheduling packet type %d \n " , type ) ;
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
if ( c )
{
if ( ! conn - > channels_to_send )
{
conn - > last_channel = c - > index ;
conn - > last_channel_count = 0 ;
}
2011-03-29 23:09:18 +00:00
2016-12-07 13:11:28 +00:00
c - > packets_to_send | = 1 < < type ;
conn - > channels_to_send | = 1 < < c - > index ;
}
else
conn - > packets_to_send | = 1 < < type ;
2000-05-04 09:03:31 +00:00
2016-12-07 13:11:28 +00:00
if ( ( conn - > sk - > tpos = = conn - > sk - > tbuf ) & & ! ev_active ( conn - > tx_ev ) )
ev_schedule ( conn - > tx_ev ) ;
}
void
bgp_kick_tx ( void * vconn )
2000-05-04 09:03:31 +00:00
{
2016-12-07 13:11:28 +00:00
struct bgp_conn * conn = vconn ;
2010-02-02 09:14:21 +00:00
2016-12-07 13:11:28 +00:00
DBG ( " BGP: kicking TX \n " ) ;
2019-06-11 09:35:25 +00:00
uint max = 1024 ;
while ( - - max & & ( bgp_fire_tx ( conn ) > 0 ) )
2016-12-07 13:11:28 +00:00
;
2019-06-11 09:35:25 +00:00
if ( ! max & & ! ev_active ( conn - > tx_ev ) )
ev_schedule ( conn - > tx_ev ) ;
2016-12-07 13:11:28 +00:00
}
2000-05-04 09:03:31 +00:00
2016-12-07 13:11:28 +00:00
void
bgp_tx ( sock * sk )
{
struct bgp_conn * conn = sk - > data ;
2000-05-04 09:03:31 +00:00
2016-12-07 13:11:28 +00:00
DBG ( " BGP: TX hook \n " ) ;
2019-06-11 09:35:25 +00:00
uint max = 1024 ;
while ( - - max & & ( bgp_fire_tx ( conn ) > 0 ) )
2016-12-07 13:11:28 +00:00
;
2019-06-11 09:35:25 +00:00
if ( ! max & & ! ev_active ( conn - > tx_ev ) )
ev_schedule ( conn - > tx_ev ) ;
2000-04-25 21:13:25 +00:00
}
2016-12-07 13:11:28 +00:00
2000-04-25 21:13:25 +00:00
static struct {
byte major , minor ;
byte * msg ;
} bgp_msg_table [ ] = {
{ 1 , 0 , " Invalid message header " } ,
{ 1 , 1 , " Connection not synchronized " } ,
{ 1 , 2 , " Bad message length " } ,
{ 1 , 3 , " Bad message type " } ,
{ 2 , 0 , " Invalid OPEN message " } ,
{ 2 , 1 , " Unsupported version number " } ,
{ 2 , 2 , " Bad peer AS " } ,
{ 2 , 3 , " Bad BGP identifier " } ,
{ 2 , 4 , " Unsupported optional parameter " } ,
{ 2 , 5 , " Authentication failure " } ,
{ 2 , 6 , " Unacceptable hold time " } ,
2015-07-18 11:38:21 +00:00
{ 2 , 7 , " Required capability missing " } , /* [RFC5492] */
2010-05-02 20:41:40 +00:00
{ 2 , 8 , " No supported AFI/SAFI " } , /* This error msg is nonstandard */
2022-07-11 15:19:34 +00:00
{ 2 , 11 , " Role mismatch " } , /* From Open Policy, RFC 9234 */
2000-04-25 21:13:25 +00:00
{ 3 , 0 , " Invalid UPDATE message " } ,
{ 3 , 1 , " Malformed attribute list " } ,
{ 3 , 2 , " Unrecognized well-known attribute " } ,
{ 3 , 3 , " Missing mandatory attribute " } ,
{ 3 , 4 , " Invalid attribute flags " } ,
{ 3 , 5 , " Invalid attribute length " } ,
{ 3 , 6 , " Invalid ORIGIN attribute " } ,
{ 3 , 7 , " AS routing loop " } , /* Deprecated */
{ 3 , 8 , " Invalid NEXT_HOP attribute " } ,
{ 3 , 9 , " Optional attribute error " } ,
{ 3 , 10 , " Invalid network field " } ,
{ 3 , 11 , " Malformed AS_PATH " } ,
{ 4 , 0 , " Hold timer expired " } ,
2013-07-25 11:55:24 +00:00
{ 5 , 0 , " Finite state machine error " } , /* Subcodes are according to [RFC6608] */
{ 5 , 1 , " Unexpected message in OpenSent state " } ,
{ 5 , 2 , " Unexpected message in OpenConfirm state " } ,
{ 5 , 3 , " Unexpected message in Established state " } ,
2008-12-24 16:24:41 +00:00
{ 6 , 0 , " Cease " } , /* Subcodes are according to [RFC4486] */
{ 6 , 1 , " Maximum number of prefixes reached " } ,
{ 6 , 2 , " Administrative shutdown " } ,
{ 6 , 3 , " Peer de-configured " } ,
{ 6 , 4 , " Administrative reset " } ,
{ 6 , 5 , " Connection rejected " } ,
{ 6 , 6 , " Other configuration change " } ,
{ 6 , 7 , " Connection collision resolution " } ,
2015-03-29 16:27:13 +00:00
{ 6 , 8 , " Out of Resources " } ,
{ 7 , 0 , " Invalid ROUTE-REFRESH message " } , /* [RFC7313] */
{ 7 , 1 , " Invalid ROUTE-REFRESH message length " } /* [RFC7313] */
2000-04-25 21:13:25 +00:00
} ;
2008-12-19 00:34:39 +00:00
/**
* bgp_error_dsc - return BGP error description
* @ code : BGP error code
* @ subcode : BGP error subcode
*
* bgp_error_dsc ( ) returns error description for BGP errors
* which might be static string or given temporary buffer .
*/
2010-04-06 22:19:23 +00:00
const char *
2016-12-07 13:11:28 +00:00
bgp_error_dsc ( uint code , uint subcode )
2008-12-19 00:34:39 +00:00
{
2010-04-06 22:19:23 +00:00
static char buff [ 32 ] ;
2016-12-07 13:11:28 +00:00
uint i ;
2008-12-19 00:34:39 +00:00
for ( i = 0 ; i < ARRAY_SIZE ( bgp_msg_table ) ; i + + )
if ( bgp_msg_table [ i ] . major = = code & & bgp_msg_table [ i ] . minor = = subcode )
2016-12-07 13:11:28 +00:00
return bgp_msg_table [ i ] . msg ;
2008-12-19 00:34:39 +00:00
2016-12-07 13:11:28 +00:00
bsprintf ( buff , " Unknown error %u.%u " , code , subcode ) ;
2008-12-19 00:34:39 +00:00
return buff ;
}
2017-09-19 17:55:37 +00:00
/* RFC 8203 - shutdown communication message */
static int
bgp_handle_message ( struct bgp_proto * p , byte * data , uint len , byte * * bp )
{
byte * msg = data + 1 ;
uint msg_len = data [ 0 ] ;
uint i ;
/* Handle zero length message */
if ( msg_len = = 0 )
return 1 ;
/* Handle proper message */
2019-09-09 01:13:35 +00:00
if ( msg_len + 1 > len )
2017-09-19 17:55:37 +00:00
return 0 ;
/* Some elementary cleanup */
for ( i = 0 ; i < msg_len ; i + + )
if ( msg [ i ] < ' ' )
msg [ i ] = ' ' ;
proto_set_message ( & p - > p , msg , msg_len ) ;
* bp + = bsprintf ( * bp , " : \" %s \" " , p - > p . message ) ;
return 1 ;
}
2000-04-25 21:13:25 +00:00
void
2016-12-07 13:11:28 +00:00
bgp_log_error ( struct bgp_proto * p , u8 class , char * msg , uint code , uint subcode , byte * data , uint len )
2000-04-25 21:13:25 +00:00
{
2019-09-09 01:13:35 +00:00
byte argbuf [ 256 + 16 ] , * t = argbuf ;
2016-12-07 13:11:28 +00:00
uint i ;
2000-04-25 21:13:25 +00:00
2009-06-06 22:38:38 +00:00
/* Don't report Cease messages generated by myself */
if ( code = = 6 & & class = = BE_BGP_TX )
2000-04-25 23:08:03 +00:00
return ;
2017-09-19 17:55:37 +00:00
/* Reset shutdown message */
if ( ( code = = 6 ) & & ( ( subcode = = 2 ) | | ( subcode = = 4 ) ) )
proto_set_message ( & p - > p , NULL , 0 ) ;
2000-04-25 21:13:25 +00:00
if ( len )
{
2022-12-10 17:03:41 +00:00
/* Bad peer AS / unacceptable hold time - print the value as decimal number */
if ( ( code = = 2 ) & & ( ( subcode = = 2 ) | | ( subcode = = 6 ) ) & & ( ( len = = 2 ) | | ( len = = 4 ) ) )
2009-09-24 21:14:44 +00:00
{
2017-09-19 17:55:37 +00:00
t + = bsprintf ( t , " : %u " , ( len = = 2 ) ? get_u16 ( data ) : get_u32 ( data ) ) ;
2009-09-24 21:14:44 +00:00
goto done ;
}
2017-09-19 17:55:37 +00:00
2023-01-20 14:55:47 +00:00
if ( ( code = = 2 ) & & ( subcode = = 11 ) & & ( len = = 1 ) )
{
t + = bsprintf ( t , " (%s) " , bgp_format_role_name ( get_u8 ( data ) ) ) ;
goto done ;
}
2017-09-19 17:55:37 +00:00
/* RFC 8203 - shutdown communication */
if ( ( ( code = = 6 ) & & ( ( subcode = = 2 ) | | ( subcode = = 4 ) ) ) )
if ( bgp_handle_message ( p , data , len , & t ) )
goto done ;
* t + + = ' : ' ;
* t + + = ' ' ;
2000-04-25 21:13:25 +00:00
if ( len > 16 )
len = 16 ;
for ( i = 0 ; i < len ; i + + )
t + = bsprintf ( t , " %02x " , data [ i ] ) ;
}
2017-09-19 17:55:37 +00:00
done :
2000-04-25 21:13:25 +00:00
* t = 0 ;
2017-09-19 17:55:37 +00:00
const byte * dsc = bgp_error_dsc ( code , subcode ) ;
log ( L_REMOTE " %s: %s: %s%s " , p - > p . name , msg , dsc , argbuf ) ;
2000-03-30 10:44:20 +00:00
}
static void
2016-10-14 13:37:04 +00:00
bgp_rx_notification ( struct bgp_conn * conn , byte * pkt , uint len )
2000-03-30 10:44:20 +00:00
{
2008-12-24 16:24:41 +00:00
struct bgp_proto * p = conn - > bgp ;
2016-12-07 13:11:28 +00:00
2000-03-30 10:44:20 +00:00
if ( len < 21 )
2016-12-07 13:11:28 +00:00
{ bgp_error ( conn , 1 , 2 , pkt + 16 , 2 ) ; return ; }
2008-12-19 00:34:39 +00:00
2016-12-07 13:11:28 +00:00
uint code = pkt [ 19 ] ;
uint subcode = pkt [ 20 ] ;
2009-06-06 22:38:38 +00:00
int err = ( code ! = 6 ) ;
2008-12-24 16:24:41 +00:00
2009-06-06 22:38:38 +00:00
bgp_log_error ( p , BE_BGP_RX , " Received " , code , subcode , pkt + 21 , len - 21 ) ;
bgp_store_error ( p , conn , BE_BGP_RX , ( code < < 16 ) | subcode ) ;
2009-03-05 10:52:47 +00:00
2023-08-21 23:24:21 +00:00
conn - > notify_code = code ;
conn - > notify_subcode = subcode ;
conn - > notify_data = pkt + 21 ;
conn - > notify_size = len - 21 ;
2008-12-19 00:34:39 +00:00
bgp_conn_enter_close_state ( conn ) ;
2016-12-07 13:11:28 +00:00
bgp_schedule_packet ( conn , NULL , PKT_SCHEDULE_CLOSE ) ;
2009-06-06 22:38:38 +00:00
2016-12-07 13:11:28 +00:00
if ( err )
{
bgp_update_startup_delay ( p ) ;
2017-12-07 20:54:47 +00:00
bgp_stop ( p , 0 , NULL , 0 ) ;
2016-12-07 13:11:28 +00:00
}
2018-01-16 18:17:04 +00:00
else
2018-01-23 17:29:32 +00:00
{
uint subcode_bit = 1 < < ( ( subcode < = 8 ) ? subcode : 0 ) ;
if ( p - > cf - > disable_after_cease & subcode_bit )
2018-01-16 18:17:04 +00:00
{
2018-01-23 17:29:32 +00:00
log ( L_INFO " %s: Disabled after Cease notification " , p - > p . name ) ;
p - > startup_delay = 0 ;
p - > p . disabled = 1 ;
2018-01-16 18:17:04 +00:00
}
2018-01-23 17:29:32 +00:00
}
2000-03-30 10:44:20 +00:00
}
static void
2004-06-05 09:27:17 +00:00
bgp_rx_keepalive ( struct bgp_conn * conn )
2000-03-30 10:44:20 +00:00
{
2000-05-02 16:07:41 +00:00
struct bgp_proto * p = conn - > bgp ;
BGP_TRACE ( D_PACKETS , " Got KEEPALIVE " ) ;
2000-03-30 10:44:20 +00:00
bgp_start_timer ( conn - > hold_timer , conn - > hold_time ) ;
2016-12-07 13:11:28 +00:00
if ( conn - > state = = BS_OPENCONFIRM )
{ bgp_conn_enter_established_state ( conn ) ; return ; }
2009-11-26 19:47:59 +00:00
if ( conn - > state ! = BS_ESTABLISHED )
2016-12-07 13:11:28 +00:00
bgp_error ( conn , 5 , fsm_err_subcode [ conn - > state ] , NULL , 0 ) ;
2009-11-26 19:47:59 +00:00
}
2000-06-04 17:06:18 +00:00
/**
* bgp_rx_packet - handle a received packet
* @ conn : BGP connection
* @ pkt : start of the packet
* @ len : packet size
*
* bgp_rx_packet ( ) takes a newly received packet and calls the corresponding
* packet handler according to the packet type .
*/
2000-03-30 10:44:20 +00:00
static void
2016-12-07 13:11:28 +00:00
bgp_rx_packet ( struct bgp_conn * conn , byte * pkt , uint len )
2000-03-30 10:44:20 +00:00
{
2010-01-03 11:17:52 +00:00
byte type = pkt [ 18 ] ;
DBG ( " BGP: Got packet %02x (%d bytes) \n " , type , len ) ;
2019-12-03 17:05:41 +00:00
conn - > bgp - > stats . rx_messages + + ;
conn - > bgp - > stats . rx_bytes + = len ;
2010-01-03 11:17:52 +00:00
if ( conn - > bgp - > p . mrtdump & MD_MESSAGES )
2018-11-20 16:38:19 +00:00
bgp_dump_message ( conn , pkt , len ) ;
2010-01-03 11:17:52 +00:00
switch ( type )
2016-12-07 13:11:28 +00:00
{
case PKT_OPEN : return bgp_rx_open ( conn , pkt , len ) ;
case PKT_UPDATE : return bgp_rx_update ( conn , pkt , len ) ;
case PKT_NOTIFICATION : return bgp_rx_notification ( conn , pkt , len ) ;
case PKT_KEEPALIVE : return bgp_rx_keepalive ( conn ) ;
case PKT_ROUTE_REFRESH : return bgp_rx_route_refresh ( conn , pkt , len ) ;
default : bgp_error ( conn , 1 , 3 , pkt + 18 , 1 ) ;
}
2000-03-21 15:53:50 +00:00
}
2024-03-08 10:31:01 +00:00
int
delete_deprecated_keys ( sock * sk , struct bgp_proto * p , int new_rnext )
2024-03-07 11:25:58 +00:00
{
struct bgp_ao_key * key = p - > ao_key ;
2024-03-08 10:31:01 +00:00
int ret = 1 ;
while ( key )
2024-03-07 11:25:58 +00:00
{
2024-03-08 10:31:01 +00:00
if ( key - > key . required = = - 1 )
{
if ( new_rnext = = key - > key . remote_id )
ret = 0 ;
else
{
if ( ao_delete_key ( sk , p - > remote_ip , - 1 , sk - > iface , key - > key . local_id , key - > key . remote_id ) )
bug ( " TCP AO: Can not delete deprecated key %i %i on socket %i " , key - > key . local_id , key - > key . remote_id , sk - > fd ) ;
key - > activ_alive = 0 ;
if ( ao_delete_key ( p - > sock - > sk , p - > remote_ip , - 1 , p - > sock - > sk - > iface , key - > key . local_id , key - > key . remote_id ) )
bug ( " TCP AO: Can not delete deprecated key %i %i on socket %i " , key - > key . local_id , key - > key . remote_id , p - > sock - > sk - > fd ) ;
key - > passiv_alive = 0 ;
}
}
2024-03-07 11:25:58 +00:00
key = key - > next_key ;
}
2024-03-08 10:31:01 +00:00
return ret ;
2024-03-07 11:25:58 +00:00
}
2000-06-04 17:06:18 +00:00
/**
* bgp_rx - handle received data
* @ sk : socket
* @ size : amount of data received
*
* bgp_rx ( ) is called by the socket layer whenever new data arrive from
* the underlying TCP connection . It assembles the data fragments to packets ,
* checks their headers and framing and passes complete packets to
* bgp_rx_packet ( ) .
*/
2000-03-21 15:53:50 +00:00
int
2016-10-14 13:37:04 +00:00
bgp_rx ( sock * sk , uint size )
2000-03-21 15:53:50 +00:00
{
struct bgp_conn * conn = sk - > data ;
2024-02-28 15:15:28 +00:00
if ( sk - > use_ao & & sk - > desired_ao_key ! = sk - > last_used_ao_key )
2024-02-26 13:58:25 +00:00
{
2024-03-07 11:25:58 +00:00
int new_rnext = get_current_key_id ( sk - > fd ) ;
2024-02-28 15:15:28 +00:00
if ( new_rnext ! = sk - > last_used_ao_key )
2024-02-26 13:58:25 +00:00
{
if ( conn - > hold_timer - > expires ! = 0 )
bgp_schedule_packet ( conn , NULL , PKT_KEEPALIVE ) ; // We might send this keepalive shortly after another. RFC says we should wait, but since reconfiguration is rare, this is harmless.
2024-03-07 11:25:58 +00:00
log ( L_INFO " TCP AO: Expected key rotation: desired rnext %i, received %i " , sk - > desired_ao_key , new_rnext ) ;
log_tcp_ao_info ( sk - > fd ) ;
if ( sk - > proto_del_ao_key & & sk - > desired_ao_key = = new_rnext )
{
2024-03-08 10:31:01 +00:00
if ( delete_deprecated_keys ( sk , sk - > proto_del_ao_key , new_rnext ) )
sk - > proto_del_ao_key = NULL ;
2024-03-07 11:25:58 +00:00
}
2024-02-28 15:15:28 +00:00
sk - > last_used_ao_key = new_rnext ;
2024-02-26 13:58:25 +00:00
}
}
2024-03-07 11:25:58 +00:00
2000-03-21 15:53:50 +00:00
byte * pkt_start = sk - > rbuf ;
byte * end = pkt_start + size ;
2016-12-07 13:11:28 +00:00
uint i , len ;
2000-03-21 15:53:50 +00:00
DBG ( " BGP: RX hook: Got %d bytes \n " , size ) ;
while ( end > = pkt_start + BGP_HEADER_LENGTH )
{
2008-12-19 00:34:39 +00:00
if ( ( conn - > state = = BS_CLOSE ) | | ( conn - > sk ! = sk ) )
return 0 ;
2000-03-30 10:44:20 +00:00
for ( i = 0 ; i < 16 ; i + + )
if ( pkt_start [ i ] ! = 0xff )
{
2000-04-25 21:13:25 +00:00
bgp_error ( conn , 1 , 1 , NULL , 0 ) ;
2000-03-30 10:44:20 +00:00
break ;
}
len = get_u16 ( pkt_start + 16 ) ;
2016-12-07 13:11:28 +00:00
if ( ( len < BGP_HEADER_LENGTH ) | | ( len > bgp_max_packet_length ( conn ) ) )
2000-03-30 10:44:20 +00:00
{
2000-04-25 21:13:25 +00:00
bgp_error ( conn , 1 , 2 , pkt_start + 16 , 2 ) ;
2000-03-30 10:44:20 +00:00
break ;
}
2000-04-19 13:54:35 +00:00
if ( end < pkt_start + len )
break ;
bgp_rx_packet ( conn , pkt_start , len ) ;
pkt_start + = len ;
2000-03-21 15:53:50 +00:00
}
if ( pkt_start ! = sk - > rbuf )
{
memmove ( sk - > rbuf , pkt_start , end - pkt_start ) ;
sk - > rpos = sk - > rbuf + ( end - pkt_start ) ;
}
return 0 ;
}