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);
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)
{
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->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);
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;
}
}
- 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;
{
/* Called only for single-hop BGP sessions */
+ /* Remove this ? */
if (ipa_zero(p->source_addr))
p->source_addr = p->neigh->iface->addr->ip;
{
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))
{
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);
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
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;
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;
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)
#else /* IPv6 version */
+static inline int
+same_iface(struct bgp_proto *p, ip_addr *ip)
+{
+ neighbor *n = neigh_find(&p->p, ip, 0);
+ return n && p->neigh && n->iface == p->neigh->iface;
+}
+
static byte *
bgp_create_update(struct bgp_conn *conn, byte *buf)
{
ip_addr *ipp, ip, ip_ll;
ea_list *ea;
eattr *nh;
- neighbor *n;
put_u16(buf, 0);
w = buf+4;
* link local address seems to be a natural way to solve that
* problem, but it is contrary to RFC 2545 and Quagga does not
* accept such routes.
+ *
+ * There are two cases, either we have global IP, or
+ * IPA_NONE if the neighbor is link-local. For IPA_NONE,
+ * we suppose it is on the same iface, see bgp_update_attrs().
*/
- n = neigh_find(&p->p, &ip, 0);
- if (n && p->neigh && n->iface == p->neigh->iface)
+ if (ipa_zero(ip) || same_iface(p, &ip))
{
if (second && ipa_nonzero(ipp[1]))
ip_ll = ipp[1];
*tmp++ = BGP_AF_IPV6;
*tmp++ = 1;
+ if (ipa_has_link_scope(ip))
+ ip = IPA_NONE;
+
if (ipa_nonzero(ip_ll))
{
*tmp++ = 32;
#ifdef IPV6
int second = (nh->u.ptr->length == NEXT_HOP_LENGTH);
+
+ /* First address should not be link-local, but may be zero in direct mode */
+ if (ipa_has_link_scope(*nexthop))
+ *nexthop = IPA_NONE;
#else
int second = 0;
#endif
if (p->cf->gw_mode == GW_DIRECT)
{
- neighbor *ng = neigh_find(&p->p, nexthop, 0) ? : p->neigh;
+ neighbor *ng;
+
+ if (ipa_nonzero(*nexthop))
+ ng = neigh_find(&p->p, nexthop, 0);
+ else if (second) /* GW_DIRECT -> single_hop -> p->neigh != NULL */
+ ng = neigh_find2(&p->p, nexthop + 1, p->neigh->iface, 0);
+
+ /* Fallback */
+ if (!ng)
+ ng = p->neigh;
+
if (ng->scope == SCOPE_HOST)
return 0;
a->igp_metric = 0;
}
else /* GW_RECURSIVE */
- rta_set_recursive_next_hop(p->p.table, a, p->igp_table, nexthop, nexthop + second);
+ {
+ if (ipa_zero(*nexthop))
+ return 0;
+
+ rta_set_recursive_next_hop(p->p.table, a, p->igp_table, nexthop, nexthop + second);
+ }
return 1;
}