max long lived stale time <number>;
};
local [<ip>] [port <number>] [as <number>];
- neighbor [<ip> | range <prefix>] [port <number>] [as <number>] [internal|external];
+ neighbor [<ip> | range <prefix>] [onlink] [port <number>] [as <number>] [internal|external];
interface "<text>";
+ onlink <switch>;
direct;
multihop [<number>];
source address <ip>;
used for non link-local sessions when it is necessary to explicitly
specify an interface, but only for direct (not multihop) sessions.
+ <tag><label id="bgp-onlink">onlink <m/switch/</tag>
+ For a direct neighbor, the BGP session starts immediately without
+ waiting for the neighbor's address to appear on any interface.
+ This option requires an interface to be configured. Next hops
+ of all routes from this session also have the <cf/onlink/ attribute.
+
+ This option may generally lead to weird behavior without other
+ configuration in place. One may e.g. need to insert a working route
+ for the given neighbor manually to allow for ACKs from the incoming
+ connection to be routed back correctly. That route may also need to
+ be announced via IGP, or <cf/next hop self/ in iBGP may be needed.
+
+ When trying setups with no neighbor route in containerized environments,
+ we got some results with <cf/strict bind/. As of Linux 6.12, we can't
+ recommend running that setup though.
+
+ Onlink behavior may also be specified inside the <cf/neighbor/ option.
+ Default: disabled.
+
<tag><label id="bgp-direct">direct</tag>
Specify that the neighbor is directly connected. The IP address of the
neighbor must be from a directly reachable IP range (i.e. associated
return;
}
- neighbor *n = neigh_find(&p->p, p->remote_ip, cf->iface, NEF_STICKY);
+ neighbor *n = neigh_find(&p->p, p->remote_ip, cf->iface, NEF_STICKY | (cf->onlink ? NEF_ONLINK : 0));
if (!n)
{
log(L_ERR "%s: Invalid remote address %I%J", p->p.name, p->remote_ip, cf->iface);
if (cf->multihop && cf->bfd && ipa_zero(cf->local_ip))
cf_error("Multihop BGP with BFD requires specified local address");
+ if (cf->multihop && cf->onlink)
+ cf_error("Multihop BGP cannot be configured onlink");
+
+ if (cf->onlink && !cf->iface)
+ cf_error("Onlink BGP must have interface configured");
+
if (!cf->gr_mode && cf->llgr_mode)
cf_error("Long-lived graceful restart requires basic graceful restart");
int multihop; /* Number of hops if multihop */
int strict_bind; /* Bind listening socket to local address */
int free_bind; /* Bind listening socket with SKF_FREEBIND */
+ int onlink; /* Enable direct connection to a host not configured on any iface */
int ttl_security; /* Enable TTL security [RFC 5082] */
int compare_path_lengths; /* Use path lengths when selecting best route */
int med_metric; /* Compare MULTI_EXIT_DISC even between routes from differen ASes */
| bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; }
| bgp_nbr_opts INTERNAL { BGP_CFG->peer_type = BGP_PT_INTERNAL; }
| bgp_nbr_opts EXTERNAL { BGP_CFG->peer_type = BGP_PT_EXTERNAL; }
+ | bgp_nbr_opts ONLINK { BGP_CFG->onlink = 1; }
;
bgp_cease_mask:
BGP_CFG->remote_range = n;
}
| bgp_proto INTERFACE text ';' { BGP_CFG->iface = if_get_by_name($3); }
+ | bgp_proto ONLINK bool ';' { BGP_CFG->onlink = $3; }
| bgp_proto RR CLUSTER ID idval ';' { BGP_CFG->rr_cluster_id = $5; }
| bgp_proto RR CLIENT bool ';' { BGP_CFG->rr_client = $4; }
| bgp_proto RS CLIENT bool ';' { BGP_CFG->rs_client = $4; }
if (c->cf->gw_mode == GW_DIRECT)
{
neighbor *nbr = NULL;
+ uint nb_flags = p->cf->onlink ? NEF_ONLINK : 0;
+ struct iface *default_iface = p->cf->onlink ? p->neigh->iface : NULL;
/* GW_DIRECT -> single_hop -> p->neigh != NULL */
if ((c->cf->next_hop_prefer == NHP_GLOBAL) && ipa_nonzero2(gw))
- nbr = neigh_find(&p->p, gw, NULL, 0);
+ nbr = neigh_find(&p->p, gw, default_iface, nb_flags);
else if (ipa_nonzero(ll))
- nbr = neigh_find(&p->p, ll, p->neigh->iface, 0);
+ nbr = neigh_find(&p->p, ll, p->neigh->iface, nb_flags);
else if (ipa_nonzero2(gw))
- nbr = neigh_find(&p->p, gw, NULL, 0);
+ nbr = neigh_find(&p->p, gw, default_iface, nb_flags);
else
WITHDRAW(BAD_NEXT_HOP " - zero address");
a->dest = RTD_UNICAST;
a->nh.gw = nbr->addr;
a->nh.iface = nbr->iface;
+ a->nh.flags = nbr->flags & NEF_ONLINK ? RNF_ONLINK : 0;
a->igp_metric = c->cf->cost;
}
else /* GW_RECURSIVE */