📄 bgp_packet.c
字号:
/* BGP packet management routine. Copyright (C) 1999 Kunihiro IshiguroThis file is part of GNU Zebra.GNU Zebra is free software; you can redistribute it and/or modify itunder the terms of the GNU General Public License as published by theFree Software Foundation; either version 2, or (at your option) anylater version.GNU Zebra is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Zebra; see the file COPYING. If not, write to the FreeSoftware Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA02111-1307, USA. */#include <zebra.h>#include "thread.h"#include "stream.h"#include "network.h"#include "prefix.h"#include "command.h"#include "log.h"#include "memory.h"#include "sockunion.h" /* for inet_ntop () */#include "linklist.h"#include "plist.h"#include "bgpd/bgpd.h"#include "bgpd/bgp_table.h"#include "bgpd/bgp_dump.h"#include "bgpd/bgp_attr.h"#include "bgpd/bgp_debug.h"#include "bgpd/bgp_fsm.h"#include "bgpd/bgp_route.h"#include "bgpd/bgp_packet.h"#include "bgpd/bgp_open.h"#include "bgpd/bgp_aspath.h"#include "bgpd/bgp_community.h"#include "bgpd/bgp_ecommunity.h"#include "bgpd/bgp_network.h"#include "bgpd/bgp_mplsvpn.h"#include "bgpd/bgp_advertise.h"int stream_put_prefix (struct stream *, struct prefix *);/* Set up BGP packet marker and packet type. */static intbgp_packet_set_marker (struct stream *s, u_char type){ int i; /* Fill in marker. */ for (i = 0; i < BGP_MARKER_SIZE; i++) stream_putc (s, 0xff); /* Dummy total length. This field is should be filled in later on. */ stream_putw (s, 0); /* BGP packet type. */ stream_putc (s, type); /* Return current stream size. */ return stream_get_putp (s);}/* Set BGP packet header size entry. If size is zero then use current stream size. */static intbgp_packet_set_size (struct stream *s){ int cp; /* Preserve current pointer. */ cp = stream_get_putp (s); stream_set_putp (s, BGP_MARKER_SIZE); stream_putw (s, cp); /* Write back current pointer. */ stream_set_putp (s, cp); return cp;}/* Add new packet to the peer. */voidbgp_packet_add (struct peer *peer, struct stream *s){ /* Add packet to the end of list. */ stream_fifo_push (peer->obuf, s);}/* Free first packet. */voidbgp_packet_delete (struct peer *peer){ stream_free (stream_fifo_pop (peer->obuf));}/* Duplicate packet. */struct stream *bgp_packet_dup (struct stream *s){ struct stream *new; new = stream_new (stream_get_endp (s)); new->endp = s->endp; new->putp = s->putp; new->getp = s->getp; memcpy (new->data, s->data, stream_get_endp (s)); return new;}/* Check file descriptor whether connect is established. */static voidbgp_connect_check (struct peer *peer){ int status; int slen; int ret; /* Anyway I have to reset read and write thread. */ BGP_READ_OFF (peer->t_read); BGP_WRITE_OFF (peer->t_write); /* Check file descriptor. */ slen = sizeof (status); ret = getsockopt(peer->fd, SOL_SOCKET, SO_ERROR, (void *) &status, &slen); /* If getsockopt is fail, this is fatal error. */ if (ret < 0) { zlog (peer->log, LOG_INFO, "can't get sockopt for nonblocking connect"); BGP_EVENT_ADD (peer, TCP_fatal_error); return; } /* When status is 0 then TCP connection is established. */ if (status == 0) { BGP_EVENT_ADD (peer, TCP_connection_open); } else { if (BGP_DEBUG (events, EVENTS)) plog_info (peer->log, "%s [Event] Connect failed (%s)", peer->host, strerror (errno)); BGP_EVENT_ADD (peer, TCP_connection_open_failed); }}/* Make BGP update packet. */struct stream *bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi){ struct stream *s; struct bgp_adj_out *adj; struct bgp_advertise *adv; struct stream *packet; struct bgp_node *rn = NULL; struct bgp_info *binfo = NULL; bgp_size_t total_attr_len = 0; unsigned long pos; char buf[BUFSIZ]; struct prefix_rd *prd = NULL; char *tag = NULL; s = peer->work; stream_reset (s); adv = FIFO_HEAD (&peer->sync[afi][safi]->update); while (adv) { if (adv->rn) rn = adv->rn; adj = adv->adj; if (adv->binfo) binfo = adv->binfo;#ifdef MPLS_VPN if (rn) prd = (struct prefix_rd *) &rn->prn->p; if (binfo) tag = binfo->tag;#endif /* MPLS_VPN */ /* When remaining space can't include NLRI and it's length. */ if (rn && STREAM_REMAIN (s) <= BGP_NLRI_LENGTH + PSIZE (rn->p.prefixlen)) break; /* If packet is empty, set attribute. */ if (stream_empty (s)) { bgp_packet_set_marker (s, BGP_MSG_UPDATE); stream_putw (s, 0); pos = stream_get_putp (s); stream_putw (s, 0); total_attr_len = bgp_packet_attribute (NULL, peer, s, adv->baa->attr, &rn->p, afi, safi, binfo->peer, prd, tag); stream_putw_at (s, pos, total_attr_len); } if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); if (BGP_DEBUG (update, UPDATE_OUT)) zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d", peer->host, inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ), rn->p.prefixlen); /* Synchnorize attribute. */ if (adj->attr) bgp_attr_unintern (adj->attr); else peer->scount[afi][safi]++; adj->attr = bgp_attr_intern (adv->baa->attr); adv = bgp_advertise_clean (peer, adj, afi, safi); if (! (afi == AFI_IP && safi == SAFI_UNICAST)) break; } if (! stream_empty (s)) { bgp_packet_set_size (s); packet = bgp_packet_dup (s); bgp_packet_add (peer, packet); stream_reset (s); return packet; } return NULL;}/* Make BGP withdraw packet. */struct stream *bgp_withdraw_packet (struct peer *peer, afi_t afi, safi_t safi){ struct stream *s; struct stream *packet; struct bgp_adj_out *adj; struct bgp_advertise *adv; struct bgp_node *rn; unsigned long pos; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; char buf[BUFSIZ]; struct prefix_rd *prd = NULL; s = peer->work; stream_reset (s); while ((adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) != NULL) { adj = adv->adj; rn = adv->rn;#ifdef MPLS_VPN prd = (struct prefix_rd *) &rn->prn->p;#endif /* MPLS_VPN */ if (STREAM_REMAIN (s) <= (BGP_NLRI_LENGTH + BGP_TOTAL_ATTR_LEN + PSIZE (rn->p.prefixlen))) break; if (stream_empty (s)) { bgp_packet_set_marker (s, BGP_MSG_UPDATE); stream_putw (s, 0); } if (afi == AFI_IP && safi == SAFI_UNICAST) stream_put_prefix (s, &rn->p); else { pos = stream_get_putp (s); stream_putw (s, 0); total_attr_len = bgp_packet_withdraw (peer, s, &rn->p, afi, safi, prd, NULL); /* Set total path attribute length. */ stream_putw_at (s, pos, total_attr_len); } if (BGP_DEBUG (update, UPDATE_OUT)) zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d -- unreachable", peer->host, inet_ntop (rn->p.family, &(rn->p.u.prefix), buf, BUFSIZ), rn->p.prefixlen); peer->scount[afi][safi]--; bgp_adj_out_remove (rn, adj, peer, afi, safi); bgp_unlock_node (rn); if (! (afi == AFI_IP && safi == SAFI_UNICAST)) break; } if (! stream_empty (s)) { if (afi == AFI_IP && safi == SAFI_UNICAST) { unfeasible_len = stream_get_putp (s) - BGP_HEADER_SIZE - BGP_UNFEASIBLE_LEN; stream_putw_at (s, BGP_HEADER_SIZE, unfeasible_len); stream_putw (s, 0); } bgp_packet_set_size (s); packet = bgp_packet_dup (s); bgp_packet_add (peer, packet); stream_reset (s); return packet; } return NULL;}voidbgp_default_update_send (struct peer *peer, struct attr *attr, afi_t afi, safi_t safi, struct peer *from){ struct stream *s; struct stream *packet; struct prefix p; unsigned long pos; bgp_size_t total_attr_len; char attrstr[BUFSIZ]; char buf[BUFSIZ];#ifdef DISABLE_BGP_ANNOUNCE return;#endif /* DISABLE_BGP_ANNOUNCE */ if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p);#ifdef HAVE_IPV6 else str2prefix ("::/0", &p);#endif /* HAVE_IPV6 */ /* Logging the attribute. */ if (BGP_DEBUG (update, UPDATE_OUT)) { bgp_dump_attr (peer, attr, attrstr, BUFSIZ); zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d %s", peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ), p.prefixlen, attrstr); } s = stream_new (BGP_MAX_PACKET_SIZE); /* Make BGP update packet. */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); /* Unfeasible Routes Length. */ stream_putw (s, 0); /* Make place for total attribute length. */ pos = stream_get_putp (s); stream_putw (s, 0); total_attr_len = bgp_packet_attribute (NULL, peer, s, attr, &p, afi, safi, from, NULL, NULL); /* Set Total Path Attribute Length. */ stream_putw_at (s, pos, total_attr_len); /* NLRI set. */ if (p.family == AF_INET && safi == SAFI_UNICAST) stream_put_prefix (s, &p); /* Set size. */ bgp_packet_set_size (s); packet = bgp_packet_dup (s); stream_free (s); /* Dump packet if debug option is set. */#ifdef DEBUG bgp_packet_dump (packet);#endif /* DEBUG */ /* Add packet to the peer. */ bgp_packet_add (peer, packet); BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);}voidbgp_default_withdraw_send (struct peer *peer, afi_t afi, safi_t safi){ struct stream *s; struct stream *packet; struct prefix p; unsigned long pos; unsigned long cp; bgp_size_t unfeasible_len; bgp_size_t total_attr_len; char buf[BUFSIZ];#ifdef DISABLE_BGP_ANNOUNCE return;#endif /* DISABLE_BGP_ANNOUNCE */ if (afi == AFI_IP) str2prefix ("0.0.0.0/0", &p);#ifdef HAVE_IPV6 else str2prefix ("::/0", &p);#endif /* HAVE_IPV6 */ total_attr_len = 0; pos = 0; if (BGP_DEBUG (update, UPDATE_OUT)) zlog (peer->log, LOG_INFO, "%s send UPDATE %s/%d -- unreachable", peer->host, inet_ntop(p.family, &(p.u.prefix), buf, BUFSIZ), p.prefixlen); s = stream_new (BGP_MAX_PACKET_SIZE); /* Make BGP update packet. */ bgp_packet_set_marker (s, BGP_MSG_UPDATE); /* Unfeasible Routes Length. */; cp = stream_get_putp (s); stream_putw (s, 0); /* Withdrawn Routes. */ if (p.family == AF_INET && safi == SAFI_UNICAST) { stream_put_prefix (s, &p); unfeasible_len = stream_get_putp (s) - cp - 2; /* Set unfeasible len. */ stream_putw_at (s, cp, unfeasible_len); /* Set total path attribute length. */ stream_putw (s, 0); } else { pos = stream_get_putp (s); stream_putw (s, 0); total_attr_len = bgp_packet_withdraw (peer, s, &p, afi, safi, NULL, NULL); /* Set total path attribute length. */ stream_putw_at (s, pos, total_attr_len); } bgp_packet_set_size (s); 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);}/* Get next packet to be written. */struct stream *bgp_write_packet (struct peer *peer){ afi_t afi; safi_t safi; struct stream *s = NULL; struct bgp_advertise *adv; s = stream_fifo_head (peer->obuf); if (s) return s; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { adv = FIFO_HEAD (&peer->sync[afi][safi]->withdraw); if (adv) { s = bgp_withdraw_packet (peer, afi, safi); if (s) return s; } } for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { adv = FIFO_HEAD (&peer->sync[afi][safi]->update); if (adv) { if (adv->binfo && adv->binfo->uptime < peer->synctime) s = bgp_update_packet (peer, afi, safi); if (s) return s; } } return NULL;}/* Is there partially written packet or updates we can send right now. */intbgp_write_proceed (struct peer *peer){ afi_t afi; safi_t safi; struct bgp_advertise *adv; if (stream_fifo_head (peer->obuf)) return 1; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) if (FIFO_HEAD (&peer->sync[afi][safi]->withdraw)) return 1; for (afi = AFI_IP; afi < AFI_MAX; afi++) for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) if ((adv = FIFO_HEAD (&peer->sync[afi][safi]->update)) != NULL) if (adv->binfo->uptime < peer->synctime) return 1; return 0;}/* Write packet to the peer. */intbgp_write (struct thread *thread){ struct peer *peer; u_char type; struct stream *s; int num; int count = 0; int write_errno; /* Yes first of all get peer pointer. */ peer = THREAD_ARG (thread); peer->t_write = NULL; /* For non-blocking IO check. */ if (peer->status == Connect) { bgp_connect_check (peer); return 0; } /* Nonblocking write until TCP output buffer is full. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -