📄 bgp_packet.c
字号:
/* Send route refresh message to the peer. */voidbgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi, u_char orf_type, u_char when_to_refresh, int remove){ struct stream *s; struct stream *packet; int length; struct bgp_filter *filter; int orf_refresh = 0;#ifdef DISABLE_BGP_ANNOUNCE return;#endif /* DISABLE_BGP_ANNOUNCE */ filter = &peer->filter[afi][safi]; /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) safi = BGP_SAFI_VPNV4; s = stream_new (BGP_MAX_PACKET_SIZE); /* Make BGP update packet. */ if (CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV)) bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_NEW); else bgp_packet_set_marker (s, BGP_MSG_ROUTE_REFRESH_OLD); /* Encode Route Refresh message. */ stream_putw (s, afi); stream_putc (s, 0); stream_putc (s, safi); if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD) if (remove || filter->plist[FILTER_IN].plist) { u_int16_t orf_len; unsigned long orfp; orf_refresh = 1; stream_putc (s, when_to_refresh); stream_putc (s, orf_type); orfp = stream_get_putp (s); stream_putw (s, 0); if (remove) { UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); stream_putc (s, ORF_COMMON_PART_REMOVE_ALL); if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s sending REFRESH_REQ to remove ORF(%d) (%s) for afi/safi: %d/%d", peer->host, orf_type, (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), afi, safi); } else { SET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_PREFIX_SEND); prefix_bgp_orf_entry (s, filter->plist[FILTER_IN].plist, ORF_COMMON_PART_ADD, ORF_COMMON_PART_PERMIT, ORF_COMMON_PART_DENY); if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s sending REFRESH_REQ with pfxlist ORF(%d) (%s) for afi/safi: %d/%d", peer->host, orf_type, (when_to_refresh == REFRESH_DEFER ? "defer" : "immediate"), afi, safi); } /* Total ORF Entry Len. */ orf_len = stream_get_putp (s) - orfp - 2; stream_putw_at (s, orfp, orf_len); } /* Set packet size. */ length = bgp_packet_set_size (s); if (BGP_DEBUG (normal, NORMAL)) { if (! orf_refresh) zlog_info ("%s sending REFRESH_REQ for afi/safi: %d/%d", peer->host, afi, safi); zlog_info ("%s send message type %d, length (incl. header) %d", peer->host, CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV) ? BGP_MSG_ROUTE_REFRESH_NEW : BGP_MSG_ROUTE_REFRESH_OLD, length); } /* Make real packet. */ packet = bgp_packet_dup (s); stream_free (s); /* Add packet to the peer. */ bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);}/* Send capability message to the peer. */voidbgp_capability_send (struct peer *peer, afi_t afi, safi_t safi, int capability_code, int action){ struct stream *s; struct stream *packet; int length; /* Adjust safi code. */ if (safi == SAFI_MPLS_VPN) safi = BGP_SAFI_VPNV4; s = stream_new (BGP_MAX_PACKET_SIZE); /* Make BGP update packet. */ bgp_packet_set_marker (s, BGP_MSG_CAPABILITY); /* Encode MP_EXT capability. */ if (capability_code == CAPABILITY_CODE_MP) { stream_putc (s, action); stream_putc (s, CAPABILITY_CODE_MP); stream_putc (s, CAPABILITY_CODE_MP_LEN); stream_putw (s, afi); stream_putc (s, 0); stream_putc (s, safi); if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s sending CAPABILITY has %s MP_EXT CAP for afi/safi: %d/%d", peer->host, action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing", afi, safi); } /* Set packet size. */ length = bgp_packet_set_size (s); /* Make real packet. */ packet = bgp_packet_dup (s); stream_free (s); /* Add packet to the peer. */ bgp_packet_add (peer, packet); if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s send message type %d, length (incl. header) %d", peer->host, BGP_MSG_CAPABILITY, length); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);}/* RFC1771 6.8 Connection collision detection. */intbgp_collision_detect (struct peer *new, struct in_addr remote_id){ struct peer *peer; struct listnode *nn; struct bgp *bgp; bgp = bgp_get_default (); if (! bgp) return 0; /* Upon receipt of an OPEN message, the local system must examine all of its connections that are in the OpenConfirm state. A BGP speaker may also examine connections in an OpenSent state if it knows the BGP Identifier of the peer by means outside of the protocol. If among these connections there is a connection to a remote BGP speaker whose BGP Identifier equals the one in the OPEN message, then the local system performs the following collision resolution procedure: */ LIST_LOOP (bgp->peer, peer, nn) { /* Under OpenConfirm status, local peer structure already hold remote router ID. */ if (peer != new && (peer->status == OpenConfirm || peer->status == OpenSent) && sockunion_same (&peer->su, &new->su)) { /* 1. The BGP Identifier of the local system is compared to the BGP Identifier of the remote system (as specified in the OPEN message). */ if (ntohl (peer->local_id.s_addr) < ntohl (remote_id.s_addr)) { /* 2. If the value of the local BGP Identifier is less than the remote one, the local system closes BGP connection that already exists (the one that is already in the OpenConfirm state), and accepts BGP connection initiated by the remote system. */ if (peer->fd >= 0) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONNECT_COLLISION); return 1; } else { /* 3. Otherwise, the local system closes newly created BGP connection (the one associated with the newly received OPEN message), and continues to use the existing one (the one that is already in the OpenConfirm state). */ if (new->fd >= 0) bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONNECT_COLLISION); return -1; } } } return 0;}intbgp_open_receive (struct peer *peer, bgp_size_t size){ int ret; u_char version; u_char optlen; u_int16_t holdtime; u_int16_t send_holdtime; as_t remote_as; struct peer *realpeer; struct in_addr remote_id; int capability; char notify_data_remote_as[2]; char notify_data_remote_id[4]; realpeer = NULL; /* Parse open packet. */ version = stream_getc (peer->ibuf); memcpy (notify_data_remote_as, stream_pnt (peer->ibuf), 2); remote_as = stream_getw (peer->ibuf); holdtime = stream_getw (peer->ibuf); memcpy (notify_data_remote_id, stream_pnt (peer->ibuf), 4); remote_id.s_addr = stream_get_ipv4 (peer->ibuf); /* Receive OPEN message log */ if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s rcv OPEN, version %d, remote-as %d, holdtime %d, id %s", peer->host, version, remote_as, holdtime, inet_ntoa (remote_id)); /* Lookup peer from Open packet. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { int as = 0; realpeer = peer_lookup_with_open (&peer->su, remote_as, &remote_id, &as); if (! realpeer) { /* Peer's source IP address is check in bgp_accept(), so this must be AS number mismatch or remote-id configuration mismatch. */ if (as) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s bad OPEN, wrong router identifier %s", peer->host, inet_ntoa (remote_id)); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_BGP_IDENT, notify_data_remote_id, 4); } else { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s bad OPEN, remote AS is %d, expected %d", peer->host, remote_as, peer->as); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); } return -1; } } /* When collision is detected and this peer is closed. Retrun immidiately. */ ret = bgp_collision_detect (peer, remote_id); if (ret < 0) return ret; /* Hack part. */ if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { if (CHECK_FLAG (realpeer->flags, PEER_FLAG_CONNECT_MODE_ACTIVE)) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s passive open failed - TCP session must be opened actively", realpeer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONNECT_REJECT); return -1; } if (realpeer->status == Established && CHECK_FLAG (realpeer->sflags, PEER_STATUS_NSF_MODE)) { realpeer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; SET_FLAG (realpeer->sflags, PEER_STATUS_NSF_WAIT); } else if (ret == 0 && realpeer->status != Active && realpeer->status != OpenSent && realpeer->status != OpenConfirm) { if (BGP_DEBUG (events, EVENTS)) zlog_info ("%s peer status is %s close connection", realpeer->host, LOOKUP (bgp_status_msg, realpeer->status)); bgp_notify_send (peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONNECT_REJECT); return -1; } if (BGP_DEBUG (events, EVENTS)) zlog_info ("%s [Event] Transfer temporary BGP peer to existing one", peer->host); bgp_stop (realpeer); /* Transfer file descriptor. */ realpeer->fd = peer->fd; peer->fd = -1; /* Transfer input buffer. */ stream_free (realpeer->ibuf); realpeer->ibuf = peer->ibuf; realpeer->packet_size = peer->packet_size; peer->ibuf = NULL; /* Transfer status. */ bgp_fsm_change_status (realpeer, peer->status); bgp_stop (peer); /* peer pointer change. Open packet send to neighbor. */ peer = realpeer; bgp_open_send (peer); if (peer->fd < 0) { zlog_err ("bgp_open_receive peer's fd is negative value %d", peer->fd); return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); } /* remote router-id check. */ if (remote_id.s_addr == 0 || ntohl (remote_id.s_addr) >= 0xe0000000 || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr)) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s bad OPEN, wrong router identifier %s", peer->host, inet_ntoa (remote_id)); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_BGP_IDENT, notify_data_remote_id, 4); return -1; } /* Set remote router-id */ peer->remote_id = remote_id; /* Peer BGP version check. */ if (version != BGP_VERSION_4) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s bad protocol version, remote requested %d, local request %d", peer->host, version, BGP_VERSION_4); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNSUP_VERSION, "\x04", 1); return -1; } /* Check neighbor as number. */ if (remote_as != peer->as) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s bad OPEN, remote AS is %d, expected %d", peer->host, remote_as, peer->as); bgp_notify_send_with_data (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return -1; } /* From the rfc: Upon receipt of an OPEN message, a BGP speaker MUST calculate the value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time received in the OPEN message. The Hold Time MUST be either zero or at least three seconds. An implementation may reject connections on the basis of the Hold Time. */ if (holdtime < 3 && holdtime != 0) { bgp_notify_send (peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); return -1; } /* From the rfc: A reasonable maximum time between KEEPALIVE messages would be one third of the Hold Time interval. KEEPALIVE messages MUST NOT be sent more frequently than one per second. An implementation MAY adjust the rate at which it sends KEEPALIVE messages as a function of the Hold Time interval. */ if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) send_holdtime = peer->holdtime; else send_holdtime = peer->bgp->default_holdtime; if (holdtime < send_holdtime) peer->v_holdtime = holdtime; else peer->v_holdtime = send_holdtime; peer->v_keepalive = peer->v_holdtime / 3; /* Open option part parse. */ capability = 0; optlen = stream_getc (peer->ibuf); if (optlen != 0) { ret = bgp_open_option_parse (peer, optlen, &capability); if (ret < 0) return ret; stream_forward (peer->ibuf, optlen); } else { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s rcvd OPEN w/ OPTION parameter len: 0", peer->host); } /* Override capability. */ if (! capability || CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) { peer->afc_nego[AFI_IP][SAFI_UNICAST] = peer->afc[AFI_IP][SAFI_UNICAST]; peer->afc_nego[AFI_IP][SAFI_MULTICAST] = peer->afc[AFI_IP][SAFI_MULTICAST]; peer->afc_nego[AFI_IP6][SAFI_UNICAST] = peer->afc[AFI_IP6][SAFI_UNICAST]; peer->afc_nego[AFI_IP6][SAFI_MULTICAST] = peer->afc[AFI_IP6][SAFI_MULTICAST]; } /* Get sockname. */ bgp_getsockname (peer); BGP_EVENT_ADD (peer, Receive_OPEN_message); peer->packet_size = 0; if (peer->ibuf) stream_reset (peer->ibuf); return 0;}/* Parse BGP Update packet and make attribute object. */intbgp_update_receive (struct peer *peer, bgp_size_t size){ int ret; u_char *end; struct stream *s; struct attr attr; bgp_size_t attribute_len; bgp_size_t update_len; bgp_size_t withdraw_len; struct bgp_nlri update; struct bgp_nlri withdraw; struct bgp_nlri mp_update; struct bgp_nlri mp_withdraw; char attrstr[BUFSIZ] = ""; /* Status must be Established. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -