Commit 53ffbff3 authored by Ondrej Zajicek's avatar Ondrej Zajicek
Browse files

Implements support for link-local addresses in BGP.

Thanks Matthias Schiffer for the original patch.
parent eb1451a3
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@

#include <errno.h>

#include "nest/iface.h"

/* we use this so that we can do without the ctype library */
#define is_digit(c)	((c) >= '0' && (c) <= '9')

@@ -138,6 +140,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
	char *str, *start;
	const char *s;
	char ipbuf[STD_ADDRESS_P_LENGTH+1];
	struct iface *iface;

	int flags;		/* flags to number() */

@@ -279,6 +282,21 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
			s = ipbuf;
			goto str;

		/* Interface scope after link-local IP address */
		case 'J':
			iface = va_arg(args, struct iface *);
			if (!iface)
				continue;
			if (!size)
				return -1;

			*str++ = '%';
			start++;
			size--;

			s = iface->name;
			goto str;

		/* Router/Network ID - essentially IPv4 address in u32 value */
		case 'R':
			x = va_arg(args, u32);
+5 −2
Original line number Diff line number Diff line
@@ -1001,10 +1001,13 @@ bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p
    }

  /* iBGP -> keep next_hop, eBGP multi-hop -> use source_addr,
     eBGP single-hop -> keep next_hop if on the same iface */
   * eBGP single-hop -> keep next_hop if on the same iface.
   * If the next_hop is zero (i.e. link-local), keep only if on the same iface.
   */
  a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
  if (a && !p->cf->next_hop_self && 
      (p->is_internal || (p->neigh && (e->attrs->iface == p->neigh->iface))))
      ((p->is_internal && ipa_nonzero(*((ip_addr *) a->u.ptr->data))) ||
       (p->neigh && (e->attrs->iface == p->neigh->iface))))
    {
      /* Leave the original next hop attribute, will check later where does it point */
    }
+23 −12
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ bgp_open(struct bgp_proto *p)

  if (p->cf->password)
    {
      int rv = sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->password);
      int rv = sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, p->cf->password);
      if (rv < 0)
	{
	  bgp_close(p, 0);
@@ -178,7 +178,7 @@ bgp_close(struct bgp_proto *p, int apply_md5)
  bgp_counter--;

  if (p->cf->password && apply_md5)
    sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, NULL);
    sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, NULL);

  if (!bgp_counter)
    {
@@ -578,6 +578,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
  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;
@@ -585,7 +586,8 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
  s->tos = IP_PREC_INTERNET_CONTROL;
  s->password = p->cf->password;
  s->tx_hook = bgp_connected;
  BGP_TRACE(D_EVENTS, "Connecting to %I from local address %I", s->daddr, s->saddr);
  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);
@@ -634,14 +636,16 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
    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))
	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 (port %d) %s",
		      sk->daddr, sk->dport, acc ? "accepted" : "rejected");
	    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;
@@ -667,7 +671,8 @@ bgp_incoming_connection(sock *sk, int dummy UNUSED)
	  }
      }

  log(L_WARN "BGP: Unexpected connect from unknown address %I (port %d)", sk->daddr, sk->dport);
  log(L_WARN "BGP: Unexpected connect from unknown address %I%J (port %d)",
      sk->daddr, ipa_has_link_scope(sk->daddr) ? sk->iface : NULL, sk->dport);
 err:
  rfree(sk);
  return 0;
@@ -713,6 +718,7 @@ bgp_start_neighbor(struct bgp_proto *p)
{
  /* Called only for single-hop BGP sessions */

  /* Remove this ? */
  if (ipa_zero(p->source_addr))
    p->source_addr = p->neigh->iface->addr->ip; 

@@ -742,7 +748,7 @@ bgp_neigh_notify(neighbor *n)
{
  struct bgp_proto *p = (struct bgp_proto *) n->proto;

  if (n->iface)
  if (n->scope > 0)
    {
      if ((p->p.proto_state == PS_START) && (p->start_state == BSS_PREPARE))
	{
@@ -793,10 +799,10 @@ bgp_start_locked(struct object_lock *lock)
      return;
    }

  p->neigh = neigh_find(&p->p, &cf->remote_ip, NEF_STICKY);
  p->neigh = neigh_find2(&p->p, &cf->remote_ip, cf->iface, NEF_STICKY);
  if (!p->neigh || (p->neigh->scope == SCOPE_HOST))
    {
      log(L_ERR "%s: Invalid remote address %I", p->p.name, cf->remote_ip);
      log(L_ERR "%s: Invalid remote address %I%J", p->p.name, cf->remote_ip, cf->iface);
      /* As we do not start yet, we can just disable protocol */
      p->p.disabled = 1;
      bgp_store_error(p, NULL, BE_MISC, BEM_INVALID_NEXT_HOP);
@@ -807,7 +813,7 @@ bgp_start_locked(struct object_lock *lock)
  if (p->neigh->scope > 0)
    bgp_start_neighbor(p);
  else
    BGP_TRACE(D_EVENTS, "Waiting for %I to become my neighbor", cf->remote_ip);
    BGP_TRACE(D_EVENTS, "Waiting for %I%J to become my neighbor", cf->remote_ip, cf->iface);
}

static int
@@ -847,6 +853,7 @@ bgp_start(struct proto *P)

  lock = p->lock = olock_new(P->pool);
  lock->addr = p->cf->remote_ip;
  lock->iface = p->cf->iface;
  lock->type = OBJLOCK_TCP;
  lock->port = BGP_PORT;
  lock->iface = NULL;
@@ -951,6 +958,10 @@ bgp_check_config(struct bgp_config *c)
  if (c->multihop && (c->gw_mode == GW_DIRECT))
    cf_error("Multihop BGP cannot use direct gateway mode");

  if (c->multihop && (ipa_has_link_scope(c->remote_ip) || 
		      ipa_has_link_scope(c->source_addr)))
    cf_error("Multihop BGP cannot be used with link-local addresses");

  /* Different default based on rs_client */
  if (!c->missing_lladdr)
    c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF;
@@ -1115,7 +1126,7 @@ bgp_show_proto_info(struct proto *P)
  struct bgp_conn *c = p->conn;

  cli_msg(-1006, "  BGP state:          %s", bgp_state_dsc(p));
  cli_msg(-1006, "    Neighbor address: %I", p->cf->remote_ip);
  cli_msg(-1006, "    Neighbor address: %I%J", p->cf->remote_ip, p->cf->iface);
  cli_msg(-1006, "    Neighbor AS:      %u", p->remote_as);

  if (P->proto_state == PS_START)
+2 −1
Original line number Diff line number Diff line
@@ -19,9 +19,10 @@ struct bgp_config {
  struct proto_config c;
  u32 local_as, remote_as;
  ip_addr remote_ip;
  ip_addr source_addr;			/* Source address to use */
  struct iface *iface;			/* Interface for link-local addresses */
  int multihop;				/* Number of hops if multihop */
  int ttl_security;			/* Enable TTL security [RFC5082] */
  ip_addr source_addr;			/* Source address to use */
  int next_hop_self;			/* Always set next hop to local IP address */
  int missing_lladdr;			/* What we will do when we don' know link-local addr, see MLL_* */
  int gw_mode;				/* How we compute route gateway from next_hop attr, see GW_* */
+7 −3
Original line number Diff line number Diff line
@@ -57,11 +57,15 @@ bgp_proto:
 | bgp_proto proto_item ';'
 | bgp_proto LOCAL AS expr ';' { BGP_CFG->local_as = $4; }
 | bgp_proto LOCAL ipa AS expr ';' { BGP_CFG->source_addr = $3; BGP_CFG->local_as = $5; }
 | bgp_proto NEIGHBOR ipa AS expr ';' {
     if (ipa_nonzero(BGP_CFG->remote_ip)) cf_error("Only one neighbor per BGP instance is allowed");
 | bgp_proto NEIGHBOR ipa ipa_scope AS expr ';' {
     if (ipa_nonzero(BGP_CFG->remote_ip))
       cf_error("Only one neighbor per BGP instance is allowed");
     if (!ipa_has_link_scope($3) != !$4)
       cf_error("Link-local address and interface scope must be used together");

     BGP_CFG->remote_ip = $3;
     BGP_CFG->remote_as = $5;
     BGP_CFG->iface = $4;
     BGP_CFG->remote_as = $6;
   }
 | bgp_proto RR CLUSTER ID idval ';' { BGP_CFG->rr_cluster_id = $5; }
 | bgp_proto RR CLIENT ';' { BGP_CFG->rr_client = 1; }
Loading