version 1.1.1.3, 2012/10/09 09:22:28
|
version 1.1.1.5, 2016/11/02 10:09:10
|
Line 27 Software Foundation, Inc., 59 Temple Place - Suite 330
|
Line 27 Software Foundation, Inc., 59 Temple Place - Suite 330
|
#include "log.h" |
#include "log.h" |
#include "command.h" |
#include "command.h" |
#include "memory.h" |
#include "memory.h" |
|
#include "filter.h" |
|
|
#include "bgpd/bgpd.h" |
#include "bgpd/bgpd.h" |
#include "bgpd/bgp_attr.h" |
#include "bgpd/bgp_attr.h" |
Line 96 bgp_capability_vty_out (struct vty *vty, struct peer *
|
Line 97 bgp_capability_vty_out (struct vty *vty, struct peer *
|
case SAFI_MPLS_LABELED_VPN: |
case SAFI_MPLS_LABELED_VPN: |
vty_out (vty, "SAFI MPLS-labeled VPN"); |
vty_out (vty, "SAFI MPLS-labeled VPN"); |
break; |
break; |
|
case SAFI_ENCAP: |
|
vty_out (vty, "SAFI ENCAP"); |
|
break; |
default: |
default: |
vty_out (vty, "SAFI Unknown %d ", mpc.safi); |
vty_out (vty, "SAFI Unknown %d ", mpc.safi); |
break; |
break; |
Line 126 bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
|
Line 130 bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)
|
{ |
{ |
switch (afi) |
switch (afi) |
{ |
{ |
case AFI_IP: | case AFI_IP: |
#ifdef HAVE_IPV6 | case AFI_IP6: |
case AFI_IP6: | switch (*safi) |
#endif | { |
switch (*safi) | /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */ |
{ | case SAFI_MPLS_LABELED_VPN: |
/* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */ | *safi = SAFI_MPLS_VPN; |
case SAFI_MPLS_LABELED_VPN: | case SAFI_UNICAST: |
*safi = SAFI_MPLS_VPN; | case SAFI_MULTICAST: |
case SAFI_UNICAST: | case SAFI_MPLS_VPN: |
case SAFI_MULTICAST: | case SAFI_ENCAP: |
case SAFI_MPLS_VPN: | return 1; |
return 1; | } |
} | break; |
} |
} |
|
|
zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi); |
zlog_debug ("unknown afi/safi (%u/%u)", afi, *safi); |
| |
return 0; |
return 0; |
} |
} |
|
|
Line 187 static const struct message orf_type_str[] =
|
Line 192 static const struct message orf_type_str[] =
|
{ ORF_TYPE_PREFIX, "Prefixlist" }, |
{ ORF_TYPE_PREFIX, "Prefixlist" }, |
{ ORF_TYPE_PREFIX_OLD, "Prefixlist (old)" }, |
{ ORF_TYPE_PREFIX_OLD, "Prefixlist (old)" }, |
}; |
}; |
static const int orf_type_str_max | static const int orf_type_str_max = array_size(orf_type_str); |
= sizeof(orf_type_str)/sizeof(orf_type_str[0]); | |
|
|
static const struct message orf_mode_str[] = |
static const struct message orf_mode_str[] = |
{ |
{ |
Line 196 static const struct message orf_mode_str[] =
|
Line 200 static const struct message orf_mode_str[] =
|
{ ORF_MODE_SEND, "Send" }, |
{ ORF_MODE_SEND, "Send" }, |
{ ORF_MODE_BOTH, "Both" }, |
{ ORF_MODE_BOTH, "Both" }, |
}; |
}; |
static const int orf_mode_str_max | static const int orf_mode_str_max = array_size(orf_mode_str); |
= sizeof(orf_mode_str)/sizeof(orf_mode_str[0]); | |
|
|
static int |
static int |
bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) |
bgp_capability_orf_entry (struct peer *peer, struct capability_header *hdr) |
Line 232 bgp_capability_orf_entry (struct peer *peer, struct ca
|
Line 235 bgp_capability_orf_entry (struct peer *peer, struct ca
|
} |
} |
|
|
/* validate number field */ |
/* validate number field */ |
if (sizeof (struct capability_orf_entry) + (entry.num * 2) > hdr->length) | if (CAPABILITY_CODE_ORF_LEN + (entry.num * 2) > hdr->length) |
{ |
{ |
zlog_info ("%s ORF Capability entry length error," |
zlog_info ("%s ORF Capability entry length error," |
" Cap length %u, num %u", |
" Cap length %u, num %u", |
peer->host, hdr->length, entry.num); |
peer->host, hdr->length, entry.num); |
bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); | bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); |
return -1; |
return -1; |
} |
} |
|
|
Line 336 bgp_capability_orf_entry (struct peer *peer, struct ca
|
Line 339 bgp_capability_orf_entry (struct peer *peer, struct ca
|
} |
} |
|
|
static int |
static int |
bgp_capability_orf (struct peer *peer, struct capability_header *hdr) |
|
{ |
|
struct stream *s = BGP_INPUT (peer); |
|
size_t end = stream_get_getp (s) + hdr->length; |
|
|
|
assert (stream_get_getp(s) + sizeof(struct capability_orf_entry) <= end); |
|
|
|
/* We must have at least one ORF entry, as the caller has already done |
|
* minimum length validation for the capability code - for ORF there must |
|
* at least one ORF entry (header and unknown number of pairs of bytes). |
|
*/ |
|
do |
|
{ |
|
if (bgp_capability_orf_entry (peer, hdr) == -1) |
|
return -1; |
|
} |
|
while (stream_get_getp(s) + sizeof(struct capability_orf_entry) < end); |
|
|
|
return 0; |
|
} |
|
|
|
static int |
|
bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) |
bgp_capability_restart (struct peer *peer, struct capability_header *caphdr) |
{ |
{ |
struct stream *s = BGP_INPUT (peer); |
struct stream *s = BGP_INPUT (peer); |
u_int16_t restart_flag_time; |
u_int16_t restart_flag_time; |
int restart_bit = 0; |
|
size_t end = stream_get_getp (s) + caphdr->length; |
size_t end = stream_get_getp (s) + caphdr->length; |
|
|
SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV); |
SET_FLAG (peer->cap, PEER_CAP_RESTART_RCV); |
restart_flag_time = stream_getw(s); |
restart_flag_time = stream_getw(s); |
if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT)) |
if (CHECK_FLAG (restart_flag_time, RESTART_R_BIT)) |
restart_bit = 1; | SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV); |
| |
UNSET_FLAG (restart_flag_time, 0xF000); |
UNSET_FLAG (restart_flag_time, 0xF000); |
peer->v_gr_restart = restart_flag_time; |
peer->v_gr_restart = restart_flag_time; |
|
|
Line 376 bgp_capability_restart (struct peer *peer, struct capa
|
Line 357 bgp_capability_restart (struct peer *peer, struct capa
|
{ |
{ |
zlog_debug ("%s OPEN has Graceful Restart capability", peer->host); |
zlog_debug ("%s OPEN has Graceful Restart capability", peer->host); |
zlog_debug ("%s Peer has%srestarted. Restart Time : %d", |
zlog_debug ("%s Peer has%srestarted. Restart Time : %d", |
peer->host, restart_bit ? " " : " not ", | peer->host, |
| CHECK_FLAG (peer->cap, PEER_CAP_RESTART_BIT_RCV) ? " " |
| : " not ", |
peer->v_gr_restart); |
peer->v_gr_restart); |
} |
} |
|
|
Line 449 static const struct message capcode_str[] =
|
Line 432 static const struct message capcode_str[] =
|
{ CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" }, |
{ CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)" }, |
{ CAPABILITY_CODE_ORF_OLD, "ORF (Old)" }, |
{ CAPABILITY_CODE_ORF_OLD, "ORF (Old)" }, |
}; |
}; |
static const int capcode_str_max = sizeof(capcode_str)/sizeof(capcode_str[0]); | static const int capcode_str_max = array_size(capcode_str); |
|
|
/* Minimum sizes for length field of each cap (so not inc. the header) */ |
/* Minimum sizes for length field of each cap (so not inc. the header) */ |
static const size_t cap_minsizes[] = |
static const size_t cap_minsizes[] = |
{ |
{ |
[CAPABILITY_CODE_MP] = sizeof (struct capability_mp_data), | [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN, |
[CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, |
[CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, |
[CAPABILITY_CODE_ORF] = sizeof (struct capability_orf_entry), | [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN, |
[CAPABILITY_CODE_RESTART] = sizeof (struct capability_gr), | [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN, |
[CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, |
[CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, |
[CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, |
[CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, |
[CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN, |
[CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN, |
[CAPABILITY_CODE_ORF_OLD] = sizeof (struct capability_orf_entry), | [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN, |
}; |
}; |
|
|
|
/* value the capability must be a multiple of. |
|
* 0-data capabilities won't be checked against this. |
|
* Other capabilities whose data doesn't fall on convenient boundaries for this |
|
* table should be set to 1. |
|
*/ |
|
static const size_t cap_modsizes[] = |
|
{ |
|
[CAPABILITY_CODE_MP] = 4, |
|
[CAPABILITY_CODE_REFRESH] = 1, |
|
[CAPABILITY_CODE_ORF] = 1, |
|
[CAPABILITY_CODE_RESTART] = 1, |
|
[CAPABILITY_CODE_AS4] = 4, |
|
[CAPABILITY_CODE_DYNAMIC] = 1, |
|
[CAPABILITY_CODE_REFRESH_OLD] = 1, |
|
[CAPABILITY_CODE_ORF_OLD] = 1, |
|
}; |
|
|
/** |
/** |
* Parse given capability. |
* Parse given capability. |
* XXX: This is reading into a stream, but not using stream API |
* XXX: This is reading into a stream, but not using stream API |
Line 491 bgp_capability_parse (struct peer *peer, size_t length
|
Line 491 bgp_capability_parse (struct peer *peer, size_t length
|
if (stream_get_getp(s) + 2 > end) |
if (stream_get_getp(s) + 2 > end) |
{ |
{ |
zlog_info ("%s Capability length error (< header)", peer->host); |
zlog_info ("%s Capability length error (< header)", peer->host); |
bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); | bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); |
return -1; |
return -1; |
} |
} |
|
|
Line 503 bgp_capability_parse (struct peer *peer, size_t length
|
Line 503 bgp_capability_parse (struct peer *peer, size_t length
|
if (start + caphdr.length > end) |
if (start + caphdr.length > end) |
{ |
{ |
zlog_info ("%s Capability length error (< length)", peer->host); |
zlog_info ("%s Capability length error (< length)", peer->host); |
bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); | bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSPECIFIC); |
return -1; |
return -1; |
} |
} |
|
|
Line 533 bgp_capability_parse (struct peer *peer, size_t length
|
Line 533 bgp_capability_parse (struct peer *peer, size_t length
|
LOOKUP (capcode_str, caphdr.code), |
LOOKUP (capcode_str, caphdr.code), |
caphdr.length, |
caphdr.length, |
(unsigned) cap_minsizes[caphdr.code]); |
(unsigned) cap_minsizes[caphdr.code]); |
bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); | bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, |
| BGP_NOTIFY_OPEN_UNSPECIFIC); |
return -1; |
return -1; |
} |
} |
|
if (caphdr.length |
|
&& caphdr.length % cap_modsizes[caphdr.code] != 0) |
|
{ |
|
zlog_info ("%s %s Capability length error: got %u," |
|
" expected a multiple of %u", |
|
peer->host, |
|
LOOKUP (capcode_str, caphdr.code), |
|
caphdr.length, |
|
(unsigned) cap_modsizes[caphdr.code]); |
|
bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, |
|
BGP_NOTIFY_OPEN_UNSPECIFIC); |
|
return -1; |
|
} |
/* we deliberately ignore unknown codes, see below */ |
/* we deliberately ignore unknown codes, see below */ |
default: |
default: |
break; |
break; |
Line 575 bgp_capability_parse (struct peer *peer, size_t length
|
Line 589 bgp_capability_parse (struct peer *peer, size_t length
|
break; |
break; |
case CAPABILITY_CODE_ORF: |
case CAPABILITY_CODE_ORF: |
case CAPABILITY_CODE_ORF_OLD: |
case CAPABILITY_CODE_ORF_OLD: |
if (bgp_capability_orf (peer, &caphdr)) | if (bgp_capability_orf_entry (peer, &caphdr)) |
return -1; |
return -1; |
break; |
break; |
case CAPABILITY_CODE_RESTART: |
case CAPABILITY_CODE_RESTART: |
Line 749 bgp_open_option_parse (struct peer *peer, u_char lengt
|
Line 763 bgp_open_option_parse (struct peer *peer, u_char lengt
|
if (STREAM_READABLE(s) < 2) |
if (STREAM_READABLE(s) < 2) |
{ |
{ |
zlog_info ("%s Option length error", peer->host); |
zlog_info ("%s Option length error", peer->host); |
bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); | bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, |
| BGP_NOTIFY_OPEN_UNSPECIFIC); |
return -1; |
return -1; |
} |
} |
|
|
Line 761 bgp_open_option_parse (struct peer *peer, u_char lengt
|
Line 776 bgp_open_option_parse (struct peer *peer, u_char lengt
|
if (STREAM_READABLE (s) < opt_length) |
if (STREAM_READABLE (s) < opt_length) |
{ |
{ |
zlog_info ("%s Option length error", peer->host); |
zlog_info ("%s Option length error", peer->host); |
bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); | bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, |
| BGP_NOTIFY_OPEN_UNSPECIFIC); |
return -1; |
return -1; |
} |
} |
|
|
Line 829 bgp_open_option_parse (struct peer *peer, u_char lengt
|
Line 845 bgp_open_option_parse (struct peer *peer, u_char lengt
|
if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] |
if (! peer->afc_nego[AFI_IP][SAFI_UNICAST] |
&& ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] |
&& ! peer->afc_nego[AFI_IP][SAFI_MULTICAST] |
&& ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] |
&& ! peer->afc_nego[AFI_IP][SAFI_MPLS_VPN] |
|
&& ! peer->afc_nego[AFI_IP][SAFI_ENCAP] |
&& ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] |
&& ! peer->afc_nego[AFI_IP6][SAFI_UNICAST] |
&& ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST]) | && ! peer->afc_nego[AFI_IP6][SAFI_MULTICAST] |
| && ! peer->afc_nego[AFI_IP6][SAFI_MPLS_VPN] |
| && ! peer->afc_nego[AFI_IP6][SAFI_ENCAP]) |
{ |
{ |
plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not " |
plog_err (peer->log, "%s [Error] Configured AFI/SAFIs do not " |
"overlap with received MP capabilities", |
"overlap with received MP capabilities", |
Line 922 void
|
Line 941 void
|
bgp_open_capability (struct stream *s, struct peer *peer) |
bgp_open_capability (struct stream *s, struct peer *peer) |
{ |
{ |
u_char len; |
u_char len; |
unsigned long cp; | unsigned long cp, capp, rcapp; |
afi_t afi; |
afi_t afi; |
safi_t safi; |
safi_t safi; |
as_t local_as; |
as_t local_as; |
|
u_int32_t restart_time; |
|
|
/* Remember current pointer for Opt Parm Len. */ |
/* Remember current pointer for Opt Parm Len. */ |
cp = stream_get_endp (s); |
cp = stream_get_endp (s); |
Line 974 bgp_open_capability (struct stream *s, struct peer *pe
|
Line 994 bgp_open_capability (struct stream *s, struct peer *pe
|
stream_putc (s, 0); |
stream_putc (s, 0); |
stream_putc (s, SAFI_MPLS_LABELED_VPN); |
stream_putc (s, SAFI_MPLS_LABELED_VPN); |
} |
} |
#ifdef HAVE_IPV6 | /* ENCAP */ |
| if (peer->afc[AFI_IP][SAFI_ENCAP]) |
| { |
| peer->afc_adv[AFI_IP][SAFI_ENCAP] = 1; |
| stream_putc (s, BGP_OPEN_OPT_CAP); |
| stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); |
| stream_putc (s, CAPABILITY_CODE_MP); |
| stream_putc (s, CAPABILITY_CODE_MP_LEN); |
| stream_putw (s, AFI_IP); |
| stream_putc (s, 0); |
| stream_putc (s, SAFI_ENCAP); |
| } |
/* IPv6 unicast. */ |
/* IPv6 unicast. */ |
if (peer->afc[AFI_IP6][SAFI_UNICAST]) |
if (peer->afc[AFI_IP6][SAFI_UNICAST]) |
{ |
{ |
Line 999 bgp_open_capability (struct stream *s, struct peer *pe
|
Line 1030 bgp_open_capability (struct stream *s, struct peer *pe
|
stream_putc (s, 0); |
stream_putc (s, 0); |
stream_putc (s, SAFI_MULTICAST); |
stream_putc (s, SAFI_MULTICAST); |
} |
} |
#endif /* HAVE_IPV6 */ | /* IPv6 VPN. */ |
| if (peer->afc[AFI_IP6][SAFI_MPLS_VPN]) |
| { |
| peer->afc_adv[AFI_IP6][SAFI_MPLS_VPN] = 1; |
| stream_putc (s, BGP_OPEN_OPT_CAP); |
| stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); |
| stream_putc (s, CAPABILITY_CODE_MP); |
| stream_putc (s, CAPABILITY_CODE_MP_LEN); |
| stream_putw (s, AFI_IP6); |
| stream_putc (s, 0); |
| stream_putc (s, SAFI_MPLS_LABELED_VPN); |
| } |
| /* IPv6 ENCAP. */ |
| if (peer->afc[AFI_IP6][SAFI_ENCAP]) |
| { |
| peer->afc_adv[AFI_IP6][SAFI_ENCAP] = 1; |
| stream_putc (s, BGP_OPEN_OPT_CAP); |
| stream_putc (s, CAPABILITY_CODE_MP_LEN + 2); |
| stream_putc (s, CAPABILITY_CODE_MP); |
| stream_putc (s, CAPABILITY_CODE_MP_LEN); |
| stream_putw (s, AFI_IP6); |
| stream_putc (s, 0); |
| stream_putc (s, SAFI_ENCAP); |
| } |
|
|
/* Route refresh. */ |
/* Route refresh. */ |
SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); |
SET_FLAG (peer->cap, PEER_CAP_REFRESH_ADV); |
Line 1044 bgp_open_capability (struct stream *s, struct peer *pe
|
Line 1098 bgp_open_capability (struct stream *s, struct peer *pe
|
stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN); |
stream_putc (s, CAPABILITY_CODE_DYNAMIC_LEN); |
} |
} |
|
|
/* Graceful restart capability */ | /* Sending base graceful-restart capability irrespective of the config */ |
| SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV); |
| stream_putc (s, BGP_OPEN_OPT_CAP); |
| capp = stream_get_endp (s); /* Set Capability Len Pointer */ |
| stream_putc (s, 0); /* Capability Length */ |
| stream_putc (s, CAPABILITY_CODE_RESTART); |
| rcapp = stream_get_endp (s); /* Set Restart Capability Len Pointer */ |
| stream_putc (s, 0); |
| restart_time = peer->bgp->restart_time; |
| if (peer->bgp->t_startup) |
| { |
| SET_FLAG (restart_time, RESTART_R_BIT); |
| SET_FLAG (peer->cap, PEER_CAP_RESTART_BIT_ADV); |
| } |
| stream_putw (s, restart_time); |
| |
| /* Send address-family specific graceful-restart capability only when GR config |
| is present */ |
if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART)) |
if (bgp_flag_check (peer->bgp, BGP_FLAG_GRACEFUL_RESTART)) |
{ |
{ |
SET_FLAG (peer->cap, PEER_CAP_RESTART_ADV); | for (afi = AFI_IP ; afi < AFI_MAX ; afi++) |
stream_putc (s, BGP_OPEN_OPT_CAP); | for (safi = SAFI_UNICAST ; safi < SAFI_MAX ; safi++) |
stream_putc (s, CAPABILITY_CODE_RESTART_LEN + 2); | if (peer->afc[afi][safi]) |
stream_putc (s, CAPABILITY_CODE_RESTART); | { |
stream_putc (s, CAPABILITY_CODE_RESTART_LEN); | stream_putw (s, afi); |
stream_putw (s, peer->bgp->restart_time); | stream_putc (s, safi); |
} | stream_putc (s, 0); //Forwarding is not retained as of now. |
| } |
| } |
| |
| /* Total Graceful restart capability Len. */ |
| len = stream_get_endp (s) - rcapp - 1; |
| stream_putc_at (s, rcapp, len); |
| |
| /* Total Capability Len. */ |
| len = stream_get_endp (s) - capp - 1; |
| stream_putc_at (s, capp, len); |
|
|
/* Total Opt Parm Len. */ |
/* Total Opt Parm Len. */ |
len = stream_get_endp (s) - cp - 1; |
len = stream_get_endp (s) - cp - 1; |