📄 bgp_packet.c
字号:
while (1) { int writenum; s = bgp_write_packet (peer); if (! s) return 0; /* Number of bytes to be sent. */ writenum = stream_get_endp (s) - stream_get_getp (s); /* Call write() system call. */ num = write (peer->fd, STREAM_PNT (s), writenum); write_errno = errno; if (num <= 0) { /* Partial write. */ if (write_errno == EWOULDBLOCK || write_errno == EAGAIN) break; bgp_stop (peer); peer->status = Idle; bgp_timer_set (peer); return 0; } if (num != writenum) { stream_forward (s, num); if (write_errno == EAGAIN) break; continue; } /* Retrieve BGP packet type. */ stream_set_getp (s, BGP_MARKER_SIZE + 2); type = stream_getc (s); switch (type) { case BGP_MSG_OPEN: peer->open_out++; break; case BGP_MSG_UPDATE: peer->update_out++; break; case BGP_MSG_NOTIFY: peer->notify_out++; /* Double start timer. */ peer->v_start *= 2; /* Overflow check. */ if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); /* BGP_EVENT_ADD (peer, BGP_Stop); */ bgp_stop (peer); peer->status = Idle; bgp_timer_set (peer); return 0; break; case BGP_MSG_KEEPALIVE: peer->keepalive_out++; break; case BGP_MSG_ROUTE_REFRESH_NEW: case BGP_MSG_ROUTE_REFRESH_OLD: peer->refresh_out++; break; case BGP_MSG_CAPABILITY: peer->dynamic_cap_out++; break; } /* OK we send packet so delete it. */ bgp_packet_delete (peer); if (++count >= BGP_WRITE_PACKET_MAX) break; } if (bgp_write_proceed (peer)) BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd); return 0;}/* This is only for sending NOTIFICATION message to neighbor. */intbgp_write_notify (struct peer *peer){ int ret; u_char type; struct stream *s; /* There should be at least one packet. */ s = stream_fifo_head (peer->obuf); if (!s) return 0; assert (stream_get_endp (s) >= BGP_HEADER_SIZE); /* I'm not sure fd is writable. */ ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s)); if (ret <= 0) { bgp_stop (peer); peer->status = Idle; bgp_timer_set (peer); return 0; } /* Retrieve BGP packet type. */ stream_set_getp (s, BGP_MARKER_SIZE + 2); type = stream_getc (s); assert (type == BGP_MSG_NOTIFY); /* Type should be notify. */ peer->notify_out++; /* Double start timer. */ peer->v_start *= 2; /* Overflow check. */ if (peer->v_start >= (60 * 2)) peer->v_start = (60 * 2); /* We don't call event manager at here for avoiding other events. */ bgp_stop (peer); peer->status = Idle; bgp_timer_set (peer); return 0;}/* Make keepalive packet and send it to the peer. */voidbgp_keepalive_send (struct peer *peer){ struct stream *s; int length; s = stream_new (BGP_MAX_PACKET_SIZE); /* Make keepalive packet. */ bgp_packet_set_marker (s, BGP_MSG_KEEPALIVE); /* Set packet size. */ length = bgp_packet_set_size (s); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ if (BGP_DEBUG (keepalive, KEEPALIVE)) zlog_info ("%s sending KEEPALIVE", peer->host); if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s send message type %d, length (incl. header) %d", peer->host, BGP_MSG_KEEPALIVE, length); /* Add packet to the peer. */ bgp_packet_add (peer, s); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);}/* Make open packet and send it to the peer. */voidbgp_open_send (struct peer *peer){ struct stream *s; int length; u_int16_t send_holdtime; as_t local_as; if (CHECK_FLAG (peer->config, PEER_CONFIG_TIMER)) send_holdtime = peer->holdtime; else send_holdtime = peer->bgp->default_holdtime; /* local-as Change */ if (peer->change_local_as) local_as = peer->change_local_as; else local_as = peer->local_as; s = stream_new (BGP_MAX_PACKET_SIZE); /* Make open packet. */ bgp_packet_set_marker (s, BGP_MSG_OPEN); /* Set open packet values. */ stream_putc (s, BGP_VERSION_4); /* BGP version */ stream_putw (s, local_as); /* My Autonomous System*/ stream_putw (s, send_holdtime); /* Hold Time */ stream_put_in_addr (s, &peer->local_id); /* BGP Identifier */ /* Set capability code. */ bgp_open_capability (s, peer); /* Set BGP packet length. */ length = bgp_packet_set_size (s); if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s sending OPEN, version %d, my as %d, holdtime %d, id %s", peer->host, BGP_VERSION_4, local_as, send_holdtime, inet_ntoa (peer->local_id)); if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s send message type %d, length (incl. header) %d", peer->host, BGP_MSG_OPEN, length); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ /* Add packet to the peer. */ bgp_packet_add (peer, s); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);}/* Send BGP notify packet with data potion. */voidbgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code, u_char *data, size_t datalen){ struct stream *s; int length; /* Allocate new stream. */ s = stream_new (BGP_MAX_PACKET_SIZE); /* Make nitify packet. */ bgp_packet_set_marker (s, BGP_MSG_NOTIFY); /* Set notify packet values. */ stream_putc (s, code); /* BGP notify code */ stream_putc (s, sub_code); /* BGP notify sub_code */ /* If notify data is present. */ if (data) stream_write (s, data, datalen); /* Set BGP packet length. */ length = bgp_packet_set_size (s); /* Add packet to the peer. */ stream_fifo_clean (peer->obuf); bgp_packet_add (peer, s); /* For debug */ { struct bgp_notify bgp_notify; int first = 0; int i; char c[4]; bgp_notify.code = code; bgp_notify.subcode = sub_code; bgp_notify.data = NULL; bgp_notify.length = length - BGP_MSG_NOTIFY_MIN_SIZE; if (bgp_notify.length) { bgp_notify.data = XMALLOC (MTYPE_TMP, bgp_notify.length * 3); for (i = 0; i < bgp_notify.length; i++) if (first) { sprintf (c, " %02x", data[i]); strcat (bgp_notify.data, c); } else { first = 1; sprintf (c, "%02x", data[i]); strcpy (bgp_notify.data, c); } } bgp_notify_print (peer, &bgp_notify, "sending"); if (bgp_notify.data) XFREE (MTYPE_TMP, bgp_notify.data); } if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s send message type %d, length (incl. header) %d", peer->host, BGP_MSG_NOTIFY, length); /* peer reset cause */ if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE) { if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET) peer->last_reset = PEER_DOWN_USER_RESET; else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) peer->last_reset = PEER_DOWN_USER_SHUTDOWN; else peer->last_reset = PEER_DOWN_NOTIFY_SEND; } /* Call imidiately. */ BGP_WRITE_OFF (peer->t_write); bgp_write_notify (peer);}/* Send BGP notify packet. */voidbgp_notify_send (struct peer *peer, u_char code, u_char sub_code){ bgp_notify_send_with_data (peer, code, sub_code, NULL, 0);}char *afi2str (afi_t afi){ if (afi == AFI_IP) return "AFI_IP"; else if (afi == AFI_IP6) return "AFI_IP6"; else return "Unknown AFI";}char *safi2str (safi_t safi){ if (safi == SAFI_UNICAST) return "SAFI_UNICAST"; else if (safi == SAFI_MULTICAST) return "SAFI_MULTICAST"; else if (safi == SAFI_MPLS_VPN || safi == BGP_SAFI_VPNV4) return "SAFI_MPLS_VPN"; else return "Unknown SAFI";}/* 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); } /* Encode Route Refresh capability. */ if (capability_code == CAPABILITY_CODE_REFRESH) { stream_putc (s, action); stream_putc (s, CAPABILITY_CODE_REFRESH); stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); stream_putc (s, action); stream_putc (s, CAPABILITY_CODE_REFRESH_OLD); stream_putc (s, CAPABILITY_CODE_REFRESH_LEN); if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s sending CAPABILITY has %s ROUTE-REFRESH capability", peer->host, action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing"); } /* 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){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -