Diff for /embedaddon/bird/proto/bgp/packets.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2017/08/22 12:33:54 version 1.1.1.2, 2021/03/17 19:50:23
Line 13 Line 13
 #include "nest/protocol.h"  #include "nest/protocol.h"
 #include "nest/route.h"  #include "nest/route.h"
 #include "nest/attrs.h"  #include "nest/attrs.h"
#include "nest/mrtdump.h"#include "proto/mrt/mrt.h"
 #include "conf/conf.h"  #include "conf/conf.h"
 #include "lib/unaligned.h"  #include "lib/unaligned.h"
 #include "lib/socket.h"  #include "lib/socket.h"
Line 38  static byte fsm_err_subcode[BS_MAX] = { Line 38  static byte fsm_err_subcode[BS_MAX] = {
   [BS_ESTABLISHED] = 3    [BS_ESTABLISHED] = 3
 };  };
   
/*static void
 * MRT Dump format is not semantically specified.init_mrt_bgp_data(struct bgp_conn *conn, struct mrt_bgp_data *d)
 * We will use these values in appropriate fields: 
 * 
 * Local AS, Remote AS - configured AS numbers for given BGP instance. 
 * Local IP, Remote IP - IP addresses of the TCP connection (0 if no connection) 
 * 
 * We dump two kinds of MRT messages: STATE_CHANGE (for BGP state 
 * changes) and MESSAGE (for received BGP messages). 
 * 
 * STATE_CHANGE uses always AS4 variant, but MESSAGE uses AS4 variant 
 * only when AS4 session is established and even in that case MESSAGE 
 * does not use AS4 variant for initial OPEN message. This strange 
 * behavior is here for compatibility with Quagga and Bgpdump, 
 */ 
 
static byte * 
mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4) 
 {  {
   struct bgp_proto *p = conn->bgp;    struct bgp_proto *p = conn->bgp;
     int p_ok = conn->state >= BS_OPENCONFIRM;
   
  if (as4)  memset(d, 0, sizeof(struct mrt_bgp_data));
    {  d->peer_as = p->remote_as;
      put_u32(buf+0, p->remote_as);  d->local_as = p->local_as;
      put_u32(buf+4, p->local_as);  d->index = (p->neigh && p->neigh->iface) ? p->neigh->iface->index : 0;
      buf+=8;  d->af = BGP_AF;
    }  d->peer_ip = conn->sk ? conn->sk->daddr : IPA_NONE;
  else  d->local_ip = conn->sk ? conn->sk->saddr : IPA_NONE;
    {  d->as4 = p_ok ? p->as4_session : 0;
      put_u16(buf+0, (p->remote_as <= 0xFFFF) ? p->remote_as : AS_TRANS);  d->add_path = p_ok ? p->add_path_rx : 0;
      put_u16(buf+2, (p->local_as <= 0xFFFF)  ? p->local_as  : AS_TRANS); 
      buf+=4; 
    } 
 
  put_u16(buf+0, (p->neigh && p->neigh->iface) ? p->neigh->iface->index : 0); 
  put_u16(buf+2, BGP_AF); 
  buf+=4; 
  buf = put_ipa(buf, conn->sk ? conn->sk->daddr : IPA_NONE); 
  buf = put_ipa(buf, conn->sk ? conn->sk->saddr : IPA_NONE); 
 
  return buf; 
 }  }
   
 static void  static void
mrt_dump_bgp_packet(struct bgp_conn *conn, byte *pkt, unsigned len)bgp_dump_message(struct bgp_conn *conn, byte *pkt, uint len)
 {  {
  byte *buf = alloca(128+len);  /* 128 is enough for MRT headers */  struct mrt_bgp_data d;
  byte *bp = buf + MRTDUMP_HDR_LENGTH;  init_mrt_bgp_data(conn, &d);
  int as4 = conn->bgp->as4_session; 
   
  bp = mrt_put_bgp4_hdr(bp, conn, as4);  d.message = pkt;
  memcpy(bp, pkt, len);  d.msg_len = len;
  bp += len; 
  mrt_dump_message(&conn->bgp->p, BGP4MP, as4 ? BGP4MP_MESSAGE_AS4 : BGP4MP_MESSAGE, 
                   buf, bp-buf); 
} 
   
static inline u16  mrt_dump_bgp_message(&d);
convert_state(unsigned state) 
{ 
  /* Convert state from our BS_* values to values used in MRTDump */ 
  return (state == BS_CLOSE) ? 1 : state + 1; 
 }  }
   
 void  void
mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new)bgp_dump_state_change(struct bgp_conn *conn, uint old, uint new)
 {  {
  byte buf[128];  struct mrt_bgp_data d;
  byte *bp = buf + MRTDUMP_HDR_LENGTH;  init_mrt_bgp_data(conn, &d);
   
  bp = mrt_put_bgp4_hdr(bp, conn, 1);  d.old_state = old;
  put_u16(bp+0, convert_state(old));  d.new_state = new;
  put_u16(bp+2, convert_state(new));
  bp += 4;  mrt_dump_bgp_state_change(&d);
  mrt_dump_message(&conn->bgp->p, BGP4MP, BGP4MP_STATE_CHANGE_AS4, buf, bp-buf); 
 }  }
   
 static byte *  static byte *
Line 231  bgp_put_cap_err(struct bgp_proto *p UNUSED, byte *buf) Line 195  bgp_put_cap_err(struct bgp_proto *p UNUSED, byte *buf)
   return buf;    return buf;
 }  }
   
   static byte *
   bgp_put_cap_llgr1(struct bgp_proto *p, byte *buf)
   {
     *buf++ = 71;          /* Capability 71: Support for long-lived graceful restart */
     *buf++ = 7;           /* Capability data length */
   
     *buf++ = 0;           /* Appropriate AF */
     *buf++ = BGP_AF;
     *buf++ = 1;           /* and SAFI 1 */
   
     /* Next is 8bit flags and 24bit time */
     put_u32(buf, p->cf->llgr_time);
     buf[0] = p->p.gr_recovery ? BGP_LLGRF_FORWARDING : 0;
     buf += 4;
   
     return buf;
   }
   
 static byte *  static byte *
   bgp_put_cap_llgr2(struct bgp_proto *p UNUSED, byte *buf)
   {
     *buf++ = 71;          /* Capability 71: Support for long-lived graceful restart */
     *buf++ = 0;           /* Capability data length */
     return buf;
   }
   
   
   static byte *
 bgp_create_open(struct bgp_conn *conn, byte *buf)  bgp_create_open(struct bgp_conn *conn, byte *buf)
 {  {
   struct bgp_proto *p = conn->bgp;    struct bgp_proto *p = conn->bgp;
Line 285  bgp_create_open(struct bgp_conn *conn, byte *buf) Line 275  bgp_create_open(struct bgp_conn *conn, byte *buf)
   if (p->cf->enable_extended_messages)    if (p->cf->enable_extended_messages)
     cap = bgp_put_cap_ext_msg(p, cap);      cap = bgp_put_cap_ext_msg(p, cap);
   
     if (p->cf->llgr_mode == BGP_LLGR_ABLE)
       cap = bgp_put_cap_llgr1(p, cap);
     else if (p->cf->llgr_mode == BGP_LLGR_AWARE)
       cap = bgp_put_cap_llgr2(p, cap);
   
   cap_len = cap - buf - 12;    cap_len = cap - buf - 12;
   if (cap_len > 0)    if (cap_len > 0)
     {      {
Line 789  bgp_kick_tx(void *vconn) Line 784  bgp_kick_tx(void *vconn)
   struct bgp_conn *conn = vconn;    struct bgp_conn *conn = vconn;
   
   DBG("BGP: kicking TX\n");    DBG("BGP: kicking TX\n");
  while (bgp_fire_tx(conn) > 0)  uint max = 1024;
   while (--max && (bgp_fire_tx(conn) > 0))
     ;      ;
   
     if (!max && !ev_active(conn->tx_ev))
       ev_schedule(conn->tx_ev);
 }  }
   
 void  void
Line 799  bgp_tx(sock *sk) Line 798  bgp_tx(sock *sk)
   struct bgp_conn *conn = sk->data;    struct bgp_conn *conn = sk->data;
   
   DBG("BGP: TX hook\n");    DBG("BGP: TX hook\n");
  while (bgp_fire_tx(conn) > 0)  uint max = 1024;
   while (--max && (bgp_fire_tx(conn) > 0))
     ;      ;
   
     if (!max && !ev_active(conn->tx_ev))
       ev_schedule(conn->tx_ev);
 }  }
   
 /* Capatibility negotiation as per RFC 2842 */  /* Capatibility negotiation as per RFC 2842 */
Line 856  bgp_parse_capabilities(struct bgp_conn *conn, byte *op Line 859  bgp_parse_capabilities(struct bgp_conn *conn, byte *op
             conn->advertised_as = get_u32(opt + 2);              conn->advertised_as = get_u32(opt + 2);
           break;            break;
   
        case 69: /* ADD-PATH capability, draft */        case 69: /* ADD-PATH capability, RFC 7911 */
           if (cl % 4)            if (cl % 4)
             goto err;              goto err;
           for (i = 0; i < cl; i += 4)            for (i = 0; i < cl; i += 4)
Line 872  bgp_parse_capabilities(struct bgp_conn *conn, byte *op Line 875  bgp_parse_capabilities(struct bgp_conn *conn, byte *op
           conn->peer_enhanced_refresh_support = 1;            conn->peer_enhanced_refresh_support = 1;
           break;            break;
   
           case 71: /* Long-lived graceful restart capability, RFC draft */
             if (cl % 7)
               goto err;
             conn->peer_llgr_aware = 1;
             conn->peer_llgr_able = 0;
             conn->peer_llgr_time = 0;
             conn->peer_llgr_aflags = 0;
             for (i = 0; i < cl; i += 7)
               if (opt[2+i+0] == 0 && opt[2+i+1] == BGP_AF && opt[2+i+2] == 1) /* Match AFI/SAFI */
                 {
                   conn->peer_llgr_able = 1;
                   conn->peer_llgr_time = get_u32(opt + 2+i+3) & 0xffffff;
                   conn->peer_llgr_aflags = opt[2+i+3];
                 }
             break;
   
           /* We can safely ignore all other capabilities */            /* We can safely ignore all other capabilities */
         }          }
       len -= 2 + cl;        len -= 2 + cl;
       opt += 2 + cl;        opt += 2 + cl;
     }      }
   
     /* The LLGR capability must be advertised together with the GR capability,
        otherwise it must be disregarded */
     if (!conn->peer_gr_aware && conn->peer_llgr_aware)
     {
       conn->peer_llgr_aware = 0;
       conn->peer_llgr_able = 0;
       conn->peer_llgr_time = 0;
       conn->peer_llgr_aflags = 0;
     }
   
   return;    return;
   
  err:   err:
Line 1034  bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len Line 1064  bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len
   p->as4_session = p->cf->enable_as4 && conn->peer_as4_support;    p->as4_session = p->cf->enable_as4 && conn->peer_as4_support;
   p->add_path_rx = (p->cf->add_path & ADD_PATH_RX) && (conn->peer_add_path & ADD_PATH_TX);    p->add_path_rx = (p->cf->add_path & ADD_PATH_RX) && (conn->peer_add_path & ADD_PATH_TX);
   p->add_path_tx = (p->cf->add_path & ADD_PATH_TX) && (conn->peer_add_path & ADD_PATH_RX);    p->add_path_tx = (p->cf->add_path & ADD_PATH_TX) && (conn->peer_add_path & ADD_PATH_RX);
  p->gr_ready = p->cf->gr_mode && conn->peer_gr_able;  p->gr_ready = (p->cf->gr_mode && conn->peer_gr_able) ||
                 (p->cf->llgr_mode && conn->peer_llgr_able);
   p->ext_messages = p->cf->enable_extended_messages && conn->peer_ext_messages_support;    p->ext_messages = p->cf->enable_extended_messages && conn->peer_ext_messages_support;
   
     /* Update RA mode */
   if (p->add_path_tx)    if (p->add_path_tx)
     p->p.accept_ra_types = RA_ANY;      p->p.accept_ra_types = RA_ANY;
     else if (p->cf->secondary)
       p->p.accept_ra_types = RA_ACCEPTED;
     else
       p->p.accept_ra_types = RA_OPTIMAL;
   
   DBG("BGP: Hold timer set to %d, keepalive to %d, AS to %d, ID to %x, AS4 session to %d\n", conn->hold_time, conn->keepalive_time, p->remote_as, p->remote_id, p->as4_session);    DBG("BGP: Hold timer set to %d, keepalive to %d, AS to %d, ID to %x, AS4 session to %d\n", conn->hold_time, conn->keepalive_time, p->remote_as, p->remote_id, p->as4_session);
   
Line 1120  bgp_rte_update(struct bgp_proto *p, ip_addr prefix, in Line 1156  bgp_rte_update(struct bgp_proto *p, ip_addr prefix, in
   e->net = n;    e->net = n;
   e->pflags = 0;    e->pflags = 0;
   e->u.bgp.suppressed = 0;    e->u.bgp.suppressed = 0;
     e->u.bgp.stale = -1;
   rte_update2(p->p.main_ahook, n, e, *src);    rte_update2(p->p.main_ahook, n, e, *src);
 }  }
   
Line 1489  bgp_error_dsc(unsigned code, unsigned subcode) Line 1526  bgp_error_dsc(unsigned code, unsigned subcode)
   return buff;    return buff;
 }  }
   
   /* RFC 8203 - shutdown communication message */
   static int
   bgp_handle_message(struct bgp_proto *p, byte *data, uint len, byte **bp)
   {
     byte *msg = data + 1;
     uint msg_len = data[0];
     uint i;
   
     /* Handle zero length message */
     if (msg_len == 0)
       return 1;
   
     /* Handle proper message */
     if (msg_len + 1 > len)
       return 0;
   
     /* Some elementary cleanup */
     for (i = 0; i < msg_len; i++)
       if (msg[i] < ' ')
         msg[i] = ' ';
   
     proto_set_message(&p->p, msg, msg_len);
     *bp += bsprintf(*bp, ": \"%s\"", p->p.message);
     return 1;
   }
   
 void  void
 bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len)  bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len)
 {  {
  const byte *name;  byte argbuf[256+16], *t = argbuf;
  byte *t, argbuf[36]; 
   unsigned i;    unsigned i;
   
   /* Don't report Cease messages generated by myself */    /* Don't report Cease messages generated by myself */
   if (code == 6 && class == BE_BGP_TX)    if (code == 6 && class == BE_BGP_TX)
     return;      return;
   
  name = bgp_error_dsc(code, subcode);  /* Reset shutdown message */
  t = argbuf;  if ((code == 6) && ((subcode == 2) || (subcode == 4)))
     proto_set_message(&p->p, NULL, 0);
 
   if (len)    if (len)
     {      {
      *t++ = ':';      /* Bad peer AS - we would like to print the AS */
      *t++ = ' '; 
 
       if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4)))        if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4)))
         {          {
          /* Bad peer AS - we would like to print the AS */          t += bsprintf(t, ": %u", (len == 2) ? get_u16(data) : get_u32(data));
          t += bsprintf(t, "%d", (len == 2) ? get_u16(data) : get_u32(data)); 
           goto done;            goto done;
         }          }
   
         /* RFC 8203 - shutdown communication */
         if (((code == 6) && ((subcode == 2) || (subcode == 4))))
           if (bgp_handle_message(p, data, len, &t))
             goto done;
   
         *t++ = ':';
         *t++ = ' ';
       if (len > 16)        if (len > 16)
         len = 16;          len = 16;
       for (i=0; i<len; i++)        for (i=0; i<len; i++)
         t += bsprintf(t, "%02x", data[i]);          t += bsprintf(t, "%02x", data[i]);
     }      }
 done:
 done:
   *t = 0;    *t = 0;
  log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf);  const byte *dsc = bgp_error_dsc(code, subcode);
   log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, dsc, argbuf);
 }  }
   
 static void  static void
Line 1566  bgp_rx_notification(struct bgp_conn *conn, byte *pkt,  Line 1637  bgp_rx_notification(struct bgp_conn *conn, byte *pkt, 
   if (err)     if (err) 
     {      {
       bgp_update_startup_delay(p);        bgp_update_startup_delay(p);
      bgp_stop(p, 0);      bgp_stop(p, 0, NULL, 0);
     }      }
     else
       {
         uint subcode_bit = 1 << ((subcode <= 8) ? subcode : 0);
         if (p->cf->disable_after_cease & subcode_bit)
         {
           log(L_INFO "%s: Disabled after Cease notification", p->p.name);
           p->startup_delay = 0;
           p->p.disabled = 1;
         }
       }
 }  }
   
 static void  static void
Line 1655  bgp_rx_packet(struct bgp_conn *conn, byte *pkt, unsign Line 1736  bgp_rx_packet(struct bgp_conn *conn, byte *pkt, unsign
   DBG("BGP: Got packet %02x (%d bytes)\n", type, len);    DBG("BGP: Got packet %02x (%d bytes)\n", type, len);
   
   if (conn->bgp->p.mrtdump & MD_MESSAGES)    if (conn->bgp->p.mrtdump & MD_MESSAGES)
    mrt_dump_bgp_packet(conn, pkt, len);    bgp_dump_message(conn, pkt, len);
   
   switch (type)    switch (type)
     {      {

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>