📄 bgp_packet.c
字号:
/* If peer does not have the capability, send notification. */ if (! CHECK_FLAG (peer->cap, PEER_CAP_REFRESH_ADV)) { plog_err (peer->log, "%s [Error] BGP route refresh is not enabled", peer->host); bgp_notify_send (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESTYPE); return; } /* Status must be Established. */ if (peer->status != Established) { plog_err (peer->log, "%s [Error] Route refresh packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); return; } s = peer->ibuf; /* Parse packet. */ afi = stream_getw (s); reserved = stream_getc (s); safi = stream_getc (s); if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s rcvd REFRESH_REQ for afi/safi: %d/%d", peer->host, afi, safi); /* Check AFI and SAFI. */ if ((afi != AFI_IP && afi != AFI_IP6) || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST && safi != BGP_SAFI_VPNV4)) { if (BGP_DEBUG (normal, NORMAL)) { zlog_info ("%s REFRESH_REQ for unrecognized afi/safi: %d/%d - ignored", peer->host, afi, safi); } return; } /* Adjust safi code. */ if (safi == BGP_SAFI_VPNV4) safi = SAFI_MPLS_VPN; if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) { u_char *end; u_char when_to_refresh; u_char orf_type; u_int16_t orf_len; if (size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) < 5) { zlog_info ("%s ORF route refresh length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return; } when_to_refresh = stream_getc (s); end = stream_pnt (s) + (size - 5); while (stream_pnt (s) < end) { orf_type = stream_getc (s); orf_len = stream_getw (s); if (orf_type == ORF_TYPE_PREFIX || orf_type == ORF_TYPE_PREFIX_OLD) { u_char *p_pnt = stream_pnt (s); u_char *p_end = stream_pnt (s) + orf_len; struct orf_prefix orfp; u_char common = 0; u_int32_t seq; int psize; char name[BUFSIZ]; char buf[BUFSIZ]; int ret; if (BGP_DEBUG (normal, NORMAL)) { zlog_info ("%s rcvd Prefixlist ORF(%d) length %d", peer->host, orf_type, orf_len); } /* ORF prefix-list name */ sprintf (name, "%s.%d.%d", peer->host, afi, safi); while (p_pnt < p_end) { memset (&orfp, 0, sizeof (struct orf_prefix)); common = *p_pnt++; if (common & ORF_COMMON_PART_REMOVE_ALL) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s rcvd Remove-All pfxlist ORF request", peer->host); prefix_bgp_orf_remove_all (name); break; } memcpy (&seq, p_pnt, sizeof (u_int32_t)); p_pnt += sizeof (u_int32_t); orfp.seq = ntohl (seq); orfp.ge = *p_pnt++; orfp.le = *p_pnt++; orfp.p.prefixlen = *p_pnt++; orfp.p.family = afi2family (afi); psize = PSIZE (orfp.p.prefixlen); memcpy (&orfp.p.u.prefix, p_pnt, psize); p_pnt += psize; if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s rcvd %s %s seq %u %s/%d ge %d le %d", peer->host, (common & ORF_COMMON_PART_REMOVE ? "Remove" : "Add"), (common & ORF_COMMON_PART_DENY ? "deny" : "permit"), orfp.seq, inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, BUFSIZ), orfp.p.prefixlen, orfp.ge, orfp.le); ret = prefix_bgp_orf_set (name, afi, &orfp, (common & ORF_COMMON_PART_DENY ? 0 : 1 ), (common & ORF_COMMON_PART_REMOVE ? 0 : 1)); if (ret != CMD_SUCCESS) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s Received misformatted prefixlist ORF. Remove All pfxlist", peer->host); prefix_bgp_orf_remove_all (name); break; } } peer->orf_plist[afi][safi] = prefix_list_lookup (AFI_ORF_PREFIX, name); } stream_forward (s, orf_len); } if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s rcvd Refresh %s ORF request", peer->host, when_to_refresh == REFRESH_DEFER ? "Defer" : "Immediate"); if (when_to_refresh == REFRESH_DEFER) return; } /* First update is deferred until ORF or ROUTE-REFRESH is received */ if (CHECK_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH)) UNSET_FLAG (peer->af_sflags[afi][safi], PEER_STATUS_ORF_WAIT_REFRESH); /* Perform route refreshment to the peer */ bgp_announce_route (peer, afi, safi);}intbgp_capability_msg_parse (struct peer *peer, u_char *pnt, bgp_size_t length){ u_char *end; struct capability cap; u_char action; struct bgp *bgp; afi_t afi; safi_t safi; bgp = peer->bgp; end = pnt + length; while (pnt < end) { /* We need at least action, capability code and capability length. */ if (pnt + 3 > end) { zlog_info ("%s Capability length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } action = *pnt; /* Fetch structure to the byte stream. */ memcpy (&cap, pnt + 1, sizeof (struct capability)); /* Action value check. */ if (action != CAPABILITY_ACTION_SET && action != CAPABILITY_ACTION_UNSET) { zlog_info ("%s Capability Action Value error %d", peer->host, action); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s CAPABILITY has action: %d, code: %u, length %u", peer->host, action, cap.code, cap.length); /* Capability length check. */ if (pnt + (cap.length + 3) > end) { zlog_info ("%s Capability length error", peer->host); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } /* We know MP Capability Code. */ if (cap.code == CAPABILITY_CODE_MP) { afi = ntohs (cap.mpc.afi); safi = cap.mpc.safi; /* Ignore capability when override-capability is set. */ if (CHECK_FLAG (peer->flags, PEER_FLAG_OVERRIDE_CAPABILITY)) continue; /* Address family check. */ if ((afi == AFI_IP || afi == AFI_IP6) && (safi == SAFI_UNICAST || safi == SAFI_MULTICAST || safi == BGP_SAFI_VPNV4)) { if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s CAPABILITY has %s MP_EXT CAP for afi/safi: %u/%u", peer->host, action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing", ntohs(cap.mpc.afi) , cap.mpc.safi); /* Adjust safi code. */ if (safi == BGP_SAFI_VPNV4) safi = SAFI_MPLS_VPN; if (action == CAPABILITY_ACTION_SET) { peer->afc_recv[afi][safi] = 1; if (peer->afc[afi][safi]) { peer->afc_nego[afi][safi] = 1; bgp_announce_route (peer, afi, safi); } } else { peer->afc_recv[afi][safi] = 0; peer->afc_nego[afi][safi] = 0; if (peer_active_nego (peer)) bgp_clear_route (peer, afi, safi); else BGP_EVENT_ADD (peer, BGP_Stop); } } } else if (cap.code == CAPABILITY_CODE_REFRESH || cap.code == CAPABILITY_CODE_REFRESH_OLD) { /* Check length. */ if (cap.length != 0) { zlog_info ("%s Route Refresh Capability length error %d", peer->host, cap.length); bgp_notify_send (peer, BGP_NOTIFY_CEASE, 0); return -1; } if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s CAPABILITY has %s ROUTE-REFRESH capability(%s) for all address-families", peer->host, action == CAPABILITY_ACTION_SET ? "Advertising" : "Removing", cap.code == CAPABILITY_CODE_REFRESH_OLD ? "old" : "new"); /* BGP refresh capability */ if (action == CAPABILITY_ACTION_SET) { if (cap.code == CAPABILITY_CODE_REFRESH_OLD) SET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); else SET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); } else { if (cap.code == CAPABILITY_CODE_REFRESH_OLD) UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_OLD_RCV); else UNSET_FLAG (peer->cap, PEER_CAP_REFRESH_NEW_RCV); } } else { zlog_warn ("%s unrecognized capability code: %d - ignored", peer->host, cap.code); } pnt += cap.length + 3; } return 0;}/* Dynamic Capability is received. */voidbgp_capability_receive (struct peer *peer, bgp_size_t size){ u_char *pnt; int ret; /* Fetch pointer. */ pnt = stream_pnt (peer->ibuf); if (BGP_DEBUG (normal, NORMAL)) zlog_info ("%s rcv CAPABILITY", peer->host); /* If peer does not have the capability, send notification. */ if (! CHECK_FLAG (peer->cap, PEER_CAP_DYNAMIC_ADV)) { plog_err (peer->log, "%s [Error] BGP dynamic capability is not enabled", peer->host); bgp_notify_send (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESTYPE); return; } /* Status must be Established. */ if (peer->status != Established) { plog_err (peer->log, "%s [Error] Dynamic capability packet received under status %s", peer->host, LOOKUP (bgp_status_msg, peer->status)); bgp_notify_send (peer, BGP_NOTIFY_FSM_ERR, 0); return; } /* Parse packet. */ ret = bgp_capability_msg_parse (peer, pnt, size);}/* BGP read utility function. */intbgp_read_packet (struct peer *peer){ int nbytes; int readsize; readsize = peer->packet_size - peer->ibuf->putp; /* If size is zero then return. */ if (! readsize) return 0; /* Read packet from fd. */ nbytes = stream_read_unblock (peer->ibuf, peer->fd, readsize); /* If read byte is smaller than zero then error occured. */ if (nbytes < 0) { if (errno == EAGAIN) return -1; plog_err (peer->log, "%s [Error] bgp_read_packet error: %s", peer->host, strerror (errno)); BGP_EVENT_ADD (peer, TCP_fatal_error); return -1; } /* When read byte is zero : clear bgp peer and return */ if (nbytes == 0) { if (BGP_DEBUG (events, EVENTS)) plog_info (peer->log, "%s [Event] BGP connection closed fd %d", peer->host, peer->fd); if (peer->status == Established) peer->last_reset = PEER_DOWN_CLOSE_SESSION; BGP_EVENT_ADD (peer, TCP_connection_closed); return -1; } /* We read partial packet. */ if (peer->ibuf->putp != peer->packet_size) return -1; return 0;}/* Marker check. */intbgp_marker_all_one (struct stream *s, int length){ int i; for (i = 0; i < length; i++) if (s->data[i] != 0xff) return 0; return 1;}/* Starting point of packet process function. */intbgp_read (struct thread *thread){ int ret; u_char type = 0; struct peer *peer; bgp_size_t size; char notify_data_length[2]; /* Yes first of all get peer pointer. */ peer = THREAD_ARG (thread); peer->t_read = NULL; /* For non-blocking IO check. */ if (peer->status == Connect) { bgp_connect_check (peer); goto done; } else { if (peer->fd < 0) { zlog_err ("bgp_read peer's fd is negative value %d", peer->fd); return -1; } BGP_READ_ON (peer->t_read, bgp_read, peer->fd); } /* Read packet header to determine type of the packet */ if (peer->packet_size == 0) peer->packet_size = BGP_HEADER_SIZE; if (peer->ibuf->putp < BGP_HEADER_SIZE) { ret = bgp_read_packet (peer); /* Header read error or partial read packet. */ if (ret < 0) goto done; /* Get size and type. */ stream_forward (peer->ibuf, BGP_MARKER_SIZE); memcpy (notify_data_length, stream_pnt (peer->ibuf), 2); size = stream_getw (peer->ibuf); type = stream_getc (peer->ibuf); if (BGP_DEBUG (normal, NORMAL) && type != 2 && type != 0) zlog_info ("%s rcv message type %d, length (excl. header) %d", peer->host, type, size - BGP_HEADER_SIZE); /* Marker check */ if (type == BGP_MSG_OPEN && ! bgp_marker_all_one (peer->ibuf, BGP_MARKER_SIZE)) { bgp_notify_send (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_NOT_SYNC); goto done; } /* BGP type check. */ if (type != BGP_MSG_OPEN && type != BGP_MSG_UPDATE && type != BGP_MSG_NOTIFY && type != BGP_MSG_KEEPALIVE && type != BGP_MSG_ROUTE_REFRESH_NEW && type != BGP_MSG_ROUTE_REFRESH_OLD && type != BGP_MSG_CAPABILITY) { if (BGP_DEBUG (normal, NORMAL)) plog_err (peer->log, "%s unknown message type 0x%02x", peer->host, type); bgp_notify_send_with_data (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESTYPE, &type, 1); goto done; } /* Mimimum packet length check. */ if ((size < BGP_HEADER_SIZE) || (size > BGP_MAX_PACKET_SIZE) || (type == BGP_MSG_OPEN && size < BGP_MSG_OPEN_MIN_SIZE) || (type == BGP_MSG_UPDATE && size < BGP_MSG_UPDATE_MIN_SIZE) || (type == BGP_MSG_NOTIFY && size < BGP_MSG_NOTIFY_MIN_SIZE) || (type == BGP_MSG_KEEPALIVE && size != BGP_MSG_KEEPALIVE_MIN_SIZE) || (type == BGP_MSG_ROUTE_REFRESH_NEW && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) || (type == BGP_MSG_ROUTE_REFRESH_OLD && size < BGP_MSG_ROUTE_REFRESH_MIN_SIZE) || (type == BGP_MSG_CAPABILITY && size < BGP_MSG_CAPABILITY_MIN_SIZE)) { if (BGP_DEBUG (normal, NORMAL)) plog_err (peer->log, "%s bad message length - %d for %s", peer->host, size, type == 128 ? "ROUTE-REFRESH" : bgp_type_str[(int) type]); bgp_notify_send_with_data (peer, BGP_NOTIFY_HEADER_ERR, BGP_NOTIFY_HEADER_BAD_MESLEN, notify_data_length, 2); goto done; } /* Adjust size to message length. */ peer->packet_size = size; } ret = bgp_read_packet (peer); if (ret < 0) goto done; /* Get size and type again. */ size = stream_getw_from (peer->ibuf, BGP_MARKER_SIZE); type = stream_getc_from (peer->ibuf, BGP_MARKER_SIZE + 2); /* BGP packet dump function. */ bgp_dump_packet (peer, type, peer->ibuf); size = (peer->packet_size - BGP_HEADER_SIZE); /* Read rest of the packet and call each sort of packet routine */ switch (type) { case BGP_MSG_OPEN: peer->open_in++; bgp_open_receive (peer, size); break; case BGP_MSG_UPDATE: peer->readtime = time(NULL); /* Last read timer reset */ bgp_update_receive (peer, size); break; case BGP_MSG_NOTIFY: bgp_notify_receive (peer, size); break; case BGP_MSG_KEEPALIVE: peer->readtime = time(NULL); /* Last read timer reset */ bgp_keepalive_receive (peer, size); break; case BGP_MSG_ROUTE_REFRESH_NEW: case BGP_MSG_ROUTE_REFRESH_OLD: peer->refresh_in++; bgp_route_refresh_receive (peer, size); break; case BGP_MSG_CAPABILITY: peer->dynamic_cap_in++; bgp_capability_receive (peer, size); break; } /* Clear input buffer. */ peer->packet_size = 0; if (peer->ibuf) stream_reset (peer->ibuf); done: if (CHECK_FLAG (peer->sflags, PEER_STATUS_ACCEPT_PEER)) { if (BGP_DEBUG (events, EVENTS)) zlog_info ("%s [Event] Accepting BGP peer delete", peer->host); peer_delete (peer); } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -