Example #1
0
File: bgp.c Project: deepfield/bird
static void
bgp_sock_err(sock *sk, int err)
{
  struct bgp_conn *conn = sk->data;
  struct bgp_proto *p = conn->bgp;

  /*
   * This error hook may be called either asynchronously from main
   * loop, or synchronously from sk_send().  But sk_send() is called
   * only from bgp_tx() and bgp_kick_tx(), which are both called
   * asynchronously from main loop. Moreover, they end if err hook is
   * called. Therefore, we could suppose that it is always called
   * asynchronously.
   */

  bgp_store_error(p, conn, BE_SOCKET, err);

  if (err)
    BGP_TRACE(D_EVENTS, "Connection lost (%M)", err);
  else
    BGP_TRACE(D_EVENTS, "Connection closed");

  if ((conn->state == BS_ESTABLISHED) && p->gr_ready)
    bgp_handle_graceful_restart(p);

  bgp_conn_enter_idle_state(conn);
}
Example #2
0
File: bgp.c Project: deepfield/bird
void
bgp_conn_enter_established_state(struct bgp_conn *conn)
{
  struct bgp_proto *p = conn->bgp;
 
  BGP_TRACE(D_EVENTS, "BGP session established");
  DBG("BGP: UP!!!\n");

  /* For multi-hop BGP sessions */
  if (ipa_zero(p->source_addr))
    p->source_addr = conn->sk->saddr;

  p->conn = conn;
  p->last_error_class = 0;
  p->last_error_code = 0;
  bgp_init_bucket_table(p);
  bgp_init_prefix_table(p, 8);

  int peer_gr_ready = conn->peer_gr_aware && !(conn->peer_gr_flags & BGP_GRF_RESTART);

  if (p->p.gr_recovery && !peer_gr_ready)
    proto_graceful_restart_unlock(&p->p);

  if (p->p.gr_recovery && (p->cf->gr_mode == BGP_GR_ABLE) && peer_gr_ready)
    p->p.gr_wait = 1;

  if (p->gr_active)
    tm_stop(p->gr_timer);

  if (p->gr_active && (!conn->peer_gr_able || !(conn->peer_gr_aflags & BGP_GRF_FORWARDING)))
    bgp_graceful_restart_done(p);

  bgp_conn_set_state(conn, BS_ESTABLISHED);
  proto_notify_state(&p->p, PS_UP);
}
Example #3
0
File: bgp.c Project: deepfield/bird
static void
bgp_graceful_restart_timeout(timer *t)
{
  struct bgp_proto *p = t->data;

  BGP_TRACE(D_EVENTS, "Neighbor graceful restart timeout");
  bgp_stop(p, 0);
}
Example #4
0
File: bgp.c Project: deepfield/bird
/**
 * bgp_graceful_restart_done - finish active BGP graceful restart
 * @p: BGP instance
 *
 * This function is called when the active BGP graceful restart of the neighbor
 * should be finished - either successfully (the neighbor sends all paths and
 * reports end-of-RIB on the new session) or unsuccessfully (the neighbor does
 * not support BGP graceful restart on the new session). The function ends
 * routing table refresh cycle and stops BGP restart timer.
 */
void
bgp_graceful_restart_done(struct bgp_proto *p)
{
  BGP_TRACE(D_EVENTS, "Neighbor graceful restart done");
  p->gr_active = 0;
  tm_stop(p->gr_timer);
  rt_refresh_end(p->p.main_ahook->table, p->p.main_ahook);
}
Example #5
0
File: bgp.c Project: rogerhu/dd-wrt
static void
bgp_down(struct bgp_proto *p)
{
    if (p->start_state > BSS_PREPARE)
        bgp_close(p, 1);

    BGP_TRACE(D_EVENTS, "Down");
    proto_notify_state(&p->p, PS_DOWN);
}
Example #6
0
File: bgp.c Project: rogerhu/dd-wrt
static void
bgp_connected(sock *sk)
{
    struct bgp_conn *conn = sk->data;
    struct bgp_proto *p = conn->bgp;

    BGP_TRACE(D_EVENTS, "Connected");
    bgp_send_open(conn);
}
Example #7
0
File: bgp.c Project: rogerhu/dd-wrt
static void
bgp_conn_leave_established_state(struct bgp_proto *p)
{
    BGP_TRACE(D_EVENTS, "BGP session closed");
    p->conn = NULL;

    if (p->p.proto_state == PS_UP)
        bgp_stop(p, 0);
}
Example #8
0
File: bgp.c Project: rogerhu/dd-wrt
static void
bgp_startup(struct bgp_proto *p)
{
    BGP_TRACE(D_EVENTS, "Started");
    p->start_state = p->cf->capabilities ? BSS_CONNECT : BSS_CONNECT_NOCAP;

    if (!p->cf->passive)
        bgp_active(p);
}
Example #9
0
File: bgp.c Project: rogerhu/dd-wrt
static void
bgp_active(struct bgp_proto *p)
{
    int delay = MAX(1, p->cf->start_delay_time);
    struct bgp_conn *conn = &p->outgoing_conn;

    BGP_TRACE(D_EVENTS, "Connect delayed by %d seconds", delay);
    bgp_setup_conn(p, conn);
    bgp_conn_set_state(conn, BS_ACTIVE);
    bgp_start_timer(conn->connect_retry_timer, delay);
}
Example #10
0
File: bgp.c Project: deepfield/bird
/**
 * bgp_incoming_connection - handle an incoming connection
 * @sk: TCP socket
 * @dummy: unused
 *
 * This function serves as a socket hook for accepting of new BGP
 * connections. It searches a BGP instance corresponding to the peer
 * which has connected and if such an instance exists, it creates a
 * &bgp_conn structure, attaches it to the instance and either sends
 * an Open message or (if there already is an active connection) it
 * closes the new connection by sending a Notification message.
 */
static int
bgp_incoming_connection(sock *sk, int dummy UNUSED)
{
  struct proto_config *pc;

  DBG("BGP: Incoming connection from %I port %d\n", sk->daddr, sk->dport);
  WALK_LIST(pc, config->protos)
    if (pc->protocol == &proto_bgp && pc->proto)
      {
	struct bgp_proto *p = (struct bgp_proto *) pc->proto;
	if (ipa_equal(p->cf->remote_ip, sk->daddr) &&
	    (!ipa_has_link_scope(sk->daddr) || (p->cf->iface == sk->iface)))
	  {
	    /* We are in proper state and there is no other incoming connection */
	    int acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) &&
	      (p->start_state >= BSS_CONNECT) && (!p->incoming_conn.sk);

	    if (p->conn && (p->conn->state == BS_ESTABLISHED) && p->gr_ready)
	    {
	      bgp_store_error(p, NULL, BE_MISC, BEM_GRACEFUL_RESTART);
	      bgp_handle_graceful_restart(p);
	      bgp_conn_enter_idle_state(p->conn);
	      acc = 1;
	    }

	    BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s",
		      sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL,
		      sk->dport, acc ? "accepted" : "rejected");

	    if (!acc)
	      goto reject;

	    int hops = p->cf->multihop ? : 1;

	    if (sk_set_ttl(sk, p->cf->ttl_security ? 255 : hops) < 0)
	      goto err;

	    if (p->cf->ttl_security)
	      if (sk_set_min_ttl(sk, 256 - hops) < 0)
		goto err;

	    bgp_setup_conn(p, &p->incoming_conn);
	    bgp_setup_sk(&p->incoming_conn, sk);
	    bgp_send_open(&p->incoming_conn);
	    return 0;

	  err:
	    sk_log_error(sk, p->p.name);
	    log(L_ERR "%s: Incoming connection aborted", p->p.name);
	    rfree(sk);
	    return 0;
	  }
      }
Example #11
0
File: bgp.c Project: rogerhu/dd-wrt
static void
bgp_initiate(struct bgp_proto *p)
{
    int rv = bgp_open(p);
    if (rv < 0)
        return;

    if (p->startup_delay)
    {
        BGP_TRACE(D_EVENTS, "Startup delayed by %d seconds", p->startup_delay);
        bgp_start_timer(p->startup_timer, p->startup_delay);
    }
    else
        bgp_startup(p);
}
Example #12
0
File: bgp.c Project: deepfield/bird
/**
 * bgp_handle_graceful_restart - handle detected BGP graceful restart
 * @p: BGP instance
 *
 * This function is called when a BGP graceful restart of the neighbor is
 * detected (when the TCP connection fails or when a new TCP connection
 * appears). The function activates processing of the restart - starts routing
 * table refresh cycle and activates BGP restart timer. The protocol state goes
 * back to %PS_START, but changing BGP state back to %BS_IDLE is left for the
 * caller.
 */
void
bgp_handle_graceful_restart(struct bgp_proto *p)
{
  ASSERT(p->conn && (p->conn->state == BS_ESTABLISHED) && p->gr_ready);

  BGP_TRACE(D_EVENTS, "Neighbor graceful restart detected%s",
	    p->gr_active ? " - already pending" : "");
  proto_notify_state(&p->p, PS_START);

  if (p->gr_active)
    rt_refresh_end(p->p.main_ahook->table, p->p.main_ahook);

  p->gr_active = 1;
  bgp_start_timer(p->gr_timer, p->conn->peer_gr_time);
  rt_refresh_begin(p->p.main_ahook->table, p->p.main_ahook);
}
Example #13
0
File: bgp.c Project: rogerhu/dd-wrt
/**
 * bgp_connect - initiate an outgoing connection
 * @p: BGP instance
 *
 * The bgp_connect() function creates a new &bgp_conn and initiates
 * a TCP connection to the peer. The rest of connection setup is governed
 * by the BGP state machine as described in the standard.
 */
static void
bgp_connect(struct bgp_proto *p)	/* Enter Connect state and start establishing connection */
{
    sock *s;
    struct bgp_conn *conn = &p->outgoing_conn;
    int hops = p->cf->multihop ? : 1;

    DBG("BGP: Connecting\n");
    s = sk_new(p->p.pool);
    s->type = SK_TCP_ACTIVE;
    s->saddr = p->source_addr;
    s->daddr = p->cf->remote_ip;
    s->iface = p->neigh ? p->neigh->iface : NULL;
    s->dport = BGP_PORT;
    s->ttl = p->cf->ttl_security ? 255 : hops;
    s->rbsize = BGP_RX_BUFFER_SIZE;
    s->tbsize = BGP_TX_BUFFER_SIZE;
    s->tos = IP_PREC_INTERNET_CONTROL;
    s->password = p->cf->password;
    s->tx_hook = bgp_connected;
    BGP_TRACE(D_EVENTS, "Connecting to %I%J from local address %I%J", s->daddr, p->cf->iface,
              s->saddr, ipa_has_link_scope(s->saddr) ? s->iface : NULL);
    bgp_setup_conn(p, conn);
    bgp_setup_sk(conn, s);
    bgp_conn_set_state(conn, BS_CONNECT);

    if (sk_open(s) < 0)
    {
        bgp_sock_err(s, 0);
        return;
    }

    /* Set minimal receive TTL if needed */
    if (p->cf->ttl_security)
    {
        DBG("Setting minimum received TTL to %d", 256 - hops);
        if (sk_set_min_ttl(s, 256 - hops) < 0)
        {
            log(L_ERR "TTL security configuration failed, closing session");
            bgp_sock_err(s, 0);
            return;
        }
    }

    DBG("BGP: Waiting for connect success\n");
    bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time);
}
Example #14
0
File: bgp.c Project: rogerhu/dd-wrt
/**
 * bgp_incoming_connection - handle an incoming connection
 * @sk: TCP socket
 * @dummy: unused
 *
 * This function serves as a socket hook for accepting of new BGP
 * connections. It searches a BGP instance corresponding to the peer
 * which has connected and if such an instance exists, it creates a
 * &bgp_conn structure, attaches it to the instance and either sends
 * an Open message or (if there already is an active connection) it
 * closes the new connection by sending a Notification message.
 */
static int
bgp_incoming_connection(sock *sk, int dummy UNUSED)
{
    struct proto_config *pc;

    DBG("BGP: Incoming connection from %I port %d\n", sk->daddr, sk->dport);
    WALK_LIST(pc, config->protos)
    if (pc->protocol == &proto_bgp && pc->proto)
    {
        struct bgp_proto *p = (struct bgp_proto *) pc->proto;
        if (ipa_equal(p->cf->remote_ip, sk->daddr) &&
                (!ipa_has_link_scope(sk->daddr) || (p->cf->iface == sk->iface)))
        {
            /* We are in proper state and there is no other incoming connection */
            int acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) &&
                      (p->start_state >= BSS_CONNECT) && (!p->incoming_conn.sk);

            BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s",
                      sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL,
                      sk->dport, acc ? "accepted" : "rejected");

            if (!acc)
                goto err;

            int hops = p->cf->multihop ? : 1;
            if (p->cf->ttl_security)
            {
                /* TTL security support */
                if ((sk_set_ttl(sk, 255) < 0) ||
                        (sk_set_min_ttl(sk, 256 - hops) < 0))
                {
                    log(L_ERR "TTL security configuration failed, closing session");
                    goto err;
                }
            }
            else
                sk_set_ttl(sk, hops);

            bgp_setup_conn(p, &p->incoming_conn);
            bgp_setup_sk(&p->incoming_conn, sk);
            bgp_send_open(&p->incoming_conn);
            return 0;
        }
    }
Example #15
0
void
bgp_conn_enter_established_state(struct bgp_conn *conn)
{
  struct bgp_proto *p = conn->bgp;

  BGP_TRACE(D_EVENTS, "BGP session established");
  DBG("BGP: UP!!!\n");

  /* For multi-hop BGP sessions */
  if (ipa_zero(p->source_addr))
    p->source_addr = conn->sk->saddr;

  p->conn = conn;
  p->last_error_class = 0;
  p->last_error_code = 0;
  p->feed_state = BFS_NONE;
  p->load_state = BFS_NONE;
  bgp_init_bucket_table(p);
  bgp_init_prefix_table(p, 8);

  int peer_gr_ready = conn->peer_gr_aware && !(conn->peer_gr_flags & BGP_GRF_RESTART);

  if (p->p.gr_recovery && !peer_gr_ready)
    proto_graceful_restart_unlock(&p->p);

  if (p->p.gr_recovery && (p->cf->gr_mode == BGP_GR_ABLE) && peer_gr_ready)
    p->p.gr_wait = 1;

  if (p->gr_active)
    tm_stop(p->gr_timer);

  if (p->gr_active && (!conn->peer_gr_able || !(conn->peer_gr_aflags & BGP_GRF_FORWARDING)))
    bgp_graceful_restart_done(p);

  /* GR capability implies that neighbor will send End-of-RIB */
  if (conn->peer_gr_aware)
    p->load_state = BFS_LOADING;

  /* proto_notify_state() will likely call bgp_feed_begin(), setting p->feed_state */

  bgp_conn_set_state(conn, BS_ESTABLISHED);
  proto_notify_state(&p->p, PS_UP);
}
Example #16
0
File: bgp.c Project: deepfield/bird
static void
bgp_initiate(struct bgp_proto *p)
{
  int rv = bgp_open(p);
  if (rv < 0)
    return;

  if (p->cf->bfd)
    bgp_update_bfd(p, p->cf->bfd);

  if (p->startup_delay)
    {
      p->start_state = BSS_DELAY;
      BGP_TRACE(D_EVENTS, "Startup delayed by %d seconds", p->startup_delay);
      bgp_start_timer(p->startup_timer, p->startup_delay);
    }
  else
    bgp_startup(p);
}
Example #17
0
/**
 * bgp_connect - initiate an outgoing connection
 * @p: BGP instance
 *
 * The bgp_connect() function creates a new &bgp_conn and initiates
 * a TCP connection to the peer. The rest of connection setup is governed
 * by the BGP state machine as described in the standard.
 */
static void
bgp_connect(struct bgp_proto *p)	/* Enter Connect state and start establishing connection */
{
  sock *s;
  struct bgp_conn *conn = &p->outgoing_conn;
  int hops = p->cf->multihop ? : 1;

  DBG("BGP: Connecting\n");
  s = sk_new(p->p.pool);
  s->type = SK_TCP_ACTIVE;
  s->saddr = p->source_addr;
  s->daddr = p->cf->remote_ip;
  s->dport = p->cf->remote_port;
  s->iface = p->neigh ? p->neigh->iface : NULL;
  s->ttl = p->cf->ttl_security ? 255 : hops;
  s->rbsize = p->cf->enable_extended_messages ? BGP_RX_BUFFER_EXT_SIZE : BGP_RX_BUFFER_SIZE;
  s->tbsize = p->cf->enable_extended_messages ? BGP_TX_BUFFER_EXT_SIZE : BGP_TX_BUFFER_SIZE;
  s->tos = IP_PREC_INTERNET_CONTROL;
  s->password = p->cf->password;
  s->tx_hook = bgp_connected;
  BGP_TRACE(D_EVENTS, "Connecting to %I%J from local address %I%J", s->daddr, p->cf->iface,
	    s->saddr, ipa_is_link_local(s->saddr) ? s->iface : NULL);
  bgp_setup_conn(p, conn);
  bgp_setup_sk(conn, s);
  bgp_conn_set_state(conn, BS_CONNECT);

  if (sk_open(s) < 0)
    goto err;

  /* Set minimal receive TTL if needed */
  if (p->cf->ttl_security)
    if (sk_set_min_ttl(s, 256 - hops) < 0)
      goto err;

  DBG("BGP: Waiting for connect success\n");
  bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time);
  return;

 err:
  sk_log_error(s, p->p.name);
  bgp_sock_err(s, 0);
  return;
}
Example #18
0
File: bgp.c Project: rogerhu/dd-wrt
void
bgp_conn_enter_established_state(struct bgp_conn *conn)
{
    struct bgp_proto *p = conn->bgp;

    BGP_TRACE(D_EVENTS, "BGP session established");
    DBG("BGP: UP!!!\n");

    /* For multi-hop BGP sessions */
    if (ipa_zero(p->source_addr))
        p->source_addr = conn->sk->saddr;

    p->conn = conn;
    p->last_error_class = 0;
    p->last_error_code = 0;
    bgp_attr_init(conn->bgp);
    bgp_conn_set_state(conn, BS_ESTABLISHED);
    proto_notify_state(&p->p, PS_UP);
}
Example #19
0
File: bgp.c Project: rogerhu/dd-wrt
static void
bgp_hold_timeout(timer *t)
{
    struct bgp_conn *conn = t->data;
    struct bgp_proto *p = conn->bgp;

    DBG("BGP: Hold timeout\n");

    /* We are already closing the connection - just do hangup */
    if (conn->state == BS_CLOSE)
    {
        BGP_TRACE(D_EVENTS, "Connection stalled");
        bgp_conn_enter_idle_state(conn);
        return;
    }

    /* If there is something in input queue, we are probably congested
       and perhaps just not processed BGP packets in time. */

    if (sk_rx_ready(conn->sk) > 0)
        bgp_start_timer(conn->hold_timer, 10);
    else
        bgp_error(conn, 4, 0, NULL, 0);
}
Example #20
0
/**
 * bgp_incoming_connection - handle an incoming connection
 * @sk: TCP socket
 * @dummy: unused
 *
 * This function serves as a socket hook for accepting of new BGP
 * connections. It searches a BGP instance corresponding to the peer
 * which has connected and if such an instance exists, it creates a
 * &bgp_conn structure, attaches it to the instance and either sends
 * an Open message or (if there already is an active connection) it
 * closes the new connection by sending a Notification message.
 */
static int
bgp_incoming_connection(sock *sk, int dummy UNUSED)
{
  struct bgp_proto *p;
  int acc, hops;

  DBG("BGP: Incoming connection from %I port %d\n", sk->daddr, sk->dport);
  p = bgp_find_proto(sk);
  if (!p)
    {
      log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)",
	  sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL, sk->dport);
      rfree(sk);
      return 0;
    }

  /* We are in proper state and there is no other incoming connection */
  acc = (p->p.proto_state == PS_START || p->p.proto_state == PS_UP) &&
    (p->start_state >= BSS_CONNECT) && (!p->incoming_conn.sk);

  if (p->conn && (p->conn->state == BS_ESTABLISHED) && p->gr_ready)
    {
      bgp_store_error(p, NULL, BE_MISC, BEM_GRACEFUL_RESTART);
      bgp_handle_graceful_restart(p);
      bgp_conn_enter_idle_state(p->conn);
      acc = 1;
    }

  BGP_TRACE(D_EVENTS, "Incoming connection from %I%J (port %d) %s",
	    sk->daddr, ipa_is_link_local(sk->daddr) ? sk->iface : NULL,
	    sk->dport, acc ? "accepted" : "rejected");

  if (!acc)
    {
      rfree(sk);
      return 0;
    }

  hops = p->cf->multihop ? : 1;

  if (sk_set_ttl(sk, p->cf->ttl_security ? 255 : hops) < 0)
    goto err;

  if (p->cf->ttl_security)
    if (sk_set_min_ttl(sk, 256 - hops) < 0)
      goto err;

  if (p->cf->enable_extended_messages)
    {
      sk->rbsize = BGP_RX_BUFFER_EXT_SIZE;
      sk->tbsize = BGP_TX_BUFFER_EXT_SIZE;
      sk_reallocate(sk);
    }

  bgp_setup_conn(p, &p->incoming_conn);
  bgp_setup_sk(&p->incoming_conn, sk);
  bgp_send_open(&p->incoming_conn);
  return 0;

err:
  sk_log_error(sk, p->p.name);
  log(L_ERR "%s: Incoming connection aborted", p->p.name);
  rfree(sk);
  return 0;
}