Merge commit '7b2c5f3d2826e3175bf31b1c36056c9efc587a2b' into int-new
This commit is contained in:
commit
46434a3cad
19 changed files with 117 additions and 12 deletions
|
@ -600,6 +600,15 @@ agreement").
|
|||
|
||||
<tag><label id="proto-table">table <m/name/</tag>
|
||||
Connect this protocol to a non-default routing table.
|
||||
|
||||
<tag><label id="proto-vrf">vrf "<m/text/"</tag>
|
||||
Associate the protocol with specific VRF. The protocol will be
|
||||
restricted to interfaces assigned to the VRF and will use sockets bound
|
||||
to the VRF. Appropriate VRF interface must exist on OS level. For kernel
|
||||
protocol, an appropriate table still must be explicitly selected by
|
||||
<cf/table/ option. Note that the VRF support in BIRD and Linux kernel
|
||||
(4.11) is still in development and is currently problematic outside of
|
||||
multihop BGP.
|
||||
</descrip>
|
||||
|
||||
<p>There are several options that give sense only with certain protocols:
|
||||
|
@ -1331,6 +1340,8 @@ foot).
|
|||
|
||||
<cf><m/P/.len</cf> returns the length of path <m/P/.
|
||||
|
||||
<cf><m/P/.empty</cf> resets path <m/P/ to empty path.
|
||||
|
||||
<cf>prepend(<m/P/,<m/A/)</cf> prepends ASN <m/A/ to path <m/P/ and
|
||||
returns the result.
|
||||
|
||||
|
@ -1369,6 +1380,8 @@ foot).
|
|||
|
||||
<cf><m/C/.len</cf> returns the length of clist <m/C/.
|
||||
|
||||
<cf><m/C/.empty</cf> resets clist <m/C/ to empty clist.
|
||||
|
||||
<cf>add(<m/C/,<m/P/)</cf> adds pair (or quad) <m/P/ to clist <m/C/ and
|
||||
returns the result. If item <m/P/ is already in clist <m/C/, it does
|
||||
nothing. <m/P/ may also be a clist, in that case all its members are
|
||||
|
|
|
@ -50,6 +50,7 @@ typedef struct birdsock {
|
|||
int ttl; /* Time To Live, -1 = default */
|
||||
u32 flags;
|
||||
struct iface *iface; /* Interface; specify this for broad/multicast sockets */
|
||||
struct iface *vrf; /* Related VRF instance, NULL if global */
|
||||
|
||||
byte *rbuf, *rpos; /* NULL=allocate automatically */
|
||||
uint fast_rx; /* RX has higher priority in event loop */
|
||||
|
|
|
@ -65,7 +65,7 @@ proto_postconfig(void)
|
|||
CF_DECLS
|
||||
|
||||
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
||||
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
|
||||
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, TABLE, STATES, ROUTES, FILTERS)
|
||||
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6)
|
||||
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
|
||||
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
|
||||
|
@ -225,6 +225,7 @@ proto_item:
|
|||
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
|
||||
| ROUTER ID idval { this_proto->router_id = $3; }
|
||||
| DESCRIPTION text { this_proto->dsc = $2; }
|
||||
| VRF text { this_proto->vrf = if_get_by_name($2); }
|
||||
;
|
||||
|
||||
|
||||
|
|
24
nest/iface.c
24
nest/iface.c
|
@ -120,7 +120,7 @@ if_what_changed(struct iface *i, struct iface *j)
|
|||
unsigned c;
|
||||
|
||||
if (((i->flags ^ j->flags) & ~(IF_UP | IF_SHUTDOWN | IF_UPDATED | IF_ADMIN_UP | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED))
|
||||
|| i->index != j->index)
|
||||
|| (i->index != j->index) || (i->master != j->master))
|
||||
return IF_CHANGE_TOO_MUCH;
|
||||
c = 0;
|
||||
if ((i->flags ^ j->flags) & IF_UP)
|
||||
|
@ -137,12 +137,16 @@ if_copy(struct iface *to, struct iface *from)
|
|||
{
|
||||
to->flags = from->flags | (to->flags & IF_TMP_DOWN);
|
||||
to->mtu = from->mtu;
|
||||
to->master_index = from->master_index;
|
||||
to->master = from->master;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
|
||||
{
|
||||
if (p->ifa_notify && (p->proto_state != PS_DOWN))
|
||||
if (p->ifa_notify &&
|
||||
(p->proto_state != PS_DOWN) &&
|
||||
(!p->vrf || p->vrf == a->iface->master))
|
||||
{
|
||||
if (p->debug & D_IFACES)
|
||||
log(L_TRACE "%s < address %N on interface %s %s",
|
||||
|
@ -178,7 +182,9 @@ ifa_notify_change(unsigned c, struct ifa *a)
|
|||
static inline void
|
||||
if_send_notify(struct proto *p, unsigned c, struct iface *i)
|
||||
{
|
||||
if (p->if_notify && (p->proto_state != PS_DOWN))
|
||||
if (p->if_notify &&
|
||||
(p->proto_state != PS_DOWN) &&
|
||||
(!p->vrf || p->vrf == i->master))
|
||||
{
|
||||
if (p->debug & D_IFACES)
|
||||
log(L_TRACE "%s < interface %s %s", p->name, i->name,
|
||||
|
@ -234,7 +240,9 @@ if_notify_change(unsigned c, struct iface *i)
|
|||
static uint
|
||||
if_recalc_flags(struct iface *i UNUSED, uint flags)
|
||||
{
|
||||
if ((flags & IF_ADMIN_UP) && !(flags & (IF_SHUTDOWN | IF_TMP_DOWN)))
|
||||
if ((flags & IF_ADMIN_UP) &&
|
||||
!(flags & (IF_SHUTDOWN | IF_TMP_DOWN)) &&
|
||||
!(i->master_index && !i->master))
|
||||
flags |= IF_UP;
|
||||
else
|
||||
flags &= ~IF_UP;
|
||||
|
@ -835,7 +843,13 @@ if_show(void)
|
|||
if (i->flags & IF_SHUTDOWN)
|
||||
continue;
|
||||
|
||||
cli_msg(-1001, "%s %s (index=%d)", i->name, (i->flags & IF_UP) ? "Up" : "Down", i->index);
|
||||
char mbuf[16 + sizeof(i->name)] = {};
|
||||
if (i->master)
|
||||
bsprintf(mbuf, " master=%s", i->master->name);
|
||||
else if (i->master_index)
|
||||
bsprintf(mbuf, " master=#%u", i->master_index);
|
||||
|
||||
cli_msg(-1001, "%s %s (index=%d%s)", i->name, (i->flags & IF_UP) ? "Up" : "Down", i->index, mbuf);
|
||||
if (!(i->flags & IF_MULTIACCESS))
|
||||
type = "PtP";
|
||||
else
|
||||
|
|
|
@ -34,6 +34,8 @@ struct iface {
|
|||
unsigned flags;
|
||||
unsigned mtu;
|
||||
unsigned index; /* OS-dependent interface index */
|
||||
unsigned master_index; /* Interface index of master iface */
|
||||
struct iface *master; /* Master iface (e.g. for VRF) */
|
||||
list addrs; /* Addresses assigned to this interface */
|
||||
struct ifa *addr4; /* Primary address for IPv4 */
|
||||
struct ifa *addr6; /* Primary address for IPv6 */
|
||||
|
|
|
@ -45,6 +45,7 @@ olock_same(struct object_lock *x, struct object_lock *y)
|
|||
return
|
||||
x->type == y->type &&
|
||||
x->iface == y->iface &&
|
||||
x->vrf == y->vrf &&
|
||||
x->port == y->port &&
|
||||
x->inst == y->inst &&
|
||||
ipa_equal(x->addr, y->addr);
|
||||
|
|
|
@ -30,6 +30,7 @@ struct object_lock {
|
|||
uint port; /* ... port number */
|
||||
uint inst; /* ... instance ID */
|
||||
struct iface *iface; /* ... interface */
|
||||
struct iface *vrf; /* ... or VRF (if iface is unknown) */
|
||||
void (*hook)(struct object_lock *); /* Called when the lock succeeds */
|
||||
void *data; /* User data */
|
||||
/* ... internal to lock manager, don't touch ... */
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
* when the protocol has explicitly requested it via the %NEF_STICKY
|
||||
* flag because it wishes to be notified when the node will again become
|
||||
* a neighbor. Such entries are enqueued in a special list which is walked
|
||||
* whenever an interface changes its state to up.
|
||||
* whenever an interface changes its state to up. Neighbor entry VRF
|
||||
* association is implied by respective protocol.
|
||||
*
|
||||
* When a neighbor event occurs (a neighbor gets disconnected or a sticky
|
||||
* inactive neighbor becomes connected), the protocol hook neigh_notify()
|
||||
|
@ -153,7 +154,8 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
|
|||
}
|
||||
else
|
||||
WALK_LIST(i, iface_list)
|
||||
if ((scope = if_connected(a, i, &addr)) >= 0)
|
||||
if ((!p->vrf || p->vrf == i->master) &&
|
||||
((scope = if_connected(a, i, &addr)) >= 0))
|
||||
{
|
||||
ifa = i;
|
||||
break;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "lib/resource.h"
|
||||
#include "lib/lists.h"
|
||||
#include "lib/event.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/string.h"
|
||||
#include "conf/conf.h"
|
||||
#include "nest/route.h"
|
||||
|
@ -673,6 +674,7 @@ proto_init(struct proto_config *c, node *n)
|
|||
|
||||
p->proto_state = PS_DOWN;
|
||||
p->last_state_change = current_time();
|
||||
p->vrf = c->vrf;
|
||||
insert_node(&p->n, n);
|
||||
|
||||
p->event = ev_new(proto_pool);
|
||||
|
@ -819,7 +821,8 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
|
|||
/* If there is a too big change in core attributes, ... */
|
||||
if ((nc->protocol != oc->protocol) ||
|
||||
(nc->net_type != oc->net_type) ||
|
||||
(nc->disabled != p->disabled))
|
||||
(nc->disabled != p->disabled) ||
|
||||
(nc->vrf != oc->vrf))
|
||||
return 0;
|
||||
|
||||
p->name = nc->name;
|
||||
|
@ -1645,6 +1648,8 @@ proto_cmd_show(struct proto *p, uint verbose, int cnt)
|
|||
cli_msg(-1006, " Description: %s", p->cf->dsc);
|
||||
if (p->cf->router_id)
|
||||
cli_msg(-1006, " Router ID: %R", p->cf->router_id);
|
||||
if (p->vrf)
|
||||
cli_msg(-1006, " VRF: %s", p->vrf->name);
|
||||
|
||||
if (p->proto->show_proto_info)
|
||||
p->proto->show_proto_info(p);
|
||||
|
|
|
@ -100,6 +100,7 @@ struct proto_config {
|
|||
u32 router_id; /* Protocol specific router ID */
|
||||
|
||||
list channels; /* List of channel configs (struct channel_config) */
|
||||
struct iface *vrf; /* Related VRF instance, NULL if global */
|
||||
|
||||
/* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
|
||||
|
||||
|
@ -142,6 +143,7 @@ struct proto {
|
|||
list channels; /* List of channels to rtables (struct channel) */
|
||||
struct channel *main_channel; /* Primary channel */
|
||||
struct rte_src *main_source; /* Primary route source */
|
||||
struct iface *vrf; /* Related VRF instance, NULL if global */
|
||||
|
||||
char *name; /* Name of this instance (== cf->name) */
|
||||
u32 debug; /* Debugging flags */
|
||||
|
|
|
@ -32,6 +32,24 @@
|
|||
* Basic FIB operations are performed by functions defined by this module,
|
||||
* enumerating of FIB contents is accomplished by using the FIB_WALK() macro
|
||||
* or FIB_ITERATE_START() if you want to do it asynchronously.
|
||||
*
|
||||
* For simple iteration just place the body of the loop between FIB_WALK() and
|
||||
* FIB_WALK_END(). You can't modify the FIB during the iteration (you can modify
|
||||
* data in the node, but not add or remove nodes).
|
||||
*
|
||||
* If you need more freedom, you can use the FIB_ITERATE_*() group of macros.
|
||||
* First, you initialize an iterator with FIB_ITERATE_INIT(). Then you can put
|
||||
* the loop body in between FIB_ITERATE_START() and FIB_ITERATE_END(). In
|
||||
* addition, the iteration can be suspended by calling FIB_ITERATE_PUT().
|
||||
* This'll link the iterator inside the FIB. While suspended, you may modify the
|
||||
* FIB, exit the current function, etc. To resume the iteration, enter the loop
|
||||
* again. You can use FIB_ITERATE_UNLINK() to unlink the iterator (while
|
||||
* iteration is suspended) in cases like premature end of FIB iteration.
|
||||
*
|
||||
* Note that the iterator must not be destroyed when the iteration is suspended,
|
||||
* the FIB would then contain a pointer to invalid memory. Therefore, after each
|
||||
* FIB_ITERATE_INIT() or FIB_ITERATE_PUT() there must be either
|
||||
* FIB_ITERATE_START() or FIB_ITERATE_UNLINK() before the iterator is destroyed.
|
||||
*/
|
||||
|
||||
#undef LOCAL_DEBUG
|
||||
|
|
|
@ -1332,6 +1332,7 @@ babel_open_socket(struct babel_iface *ifa)
|
|||
sk->dport = ifa->cf->port;
|
||||
sk->iface = ifa->iface;
|
||||
sk->saddr = ifa->addr;
|
||||
sk->vrf = p->p.vrf;
|
||||
|
||||
sk->rx_hook = babel_rx_hook;
|
||||
sk->tx_hook = babel_tx_hook;
|
||||
|
|
|
@ -939,6 +939,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
|
|||
s->daddr = p->cf->remote_ip;
|
||||
s->dport = p->cf->remote_port;
|
||||
s->iface = p->neigh ? p->neigh->iface : NULL;
|
||||
s->vrf = p->p.vrf;
|
||||
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;
|
||||
|
@ -1331,6 +1332,7 @@ bgp_start(struct proto *P)
|
|||
lock->addr = p->cf->remote_ip;
|
||||
lock->port = p->cf->remote_port;
|
||||
lock->iface = p->cf->iface;
|
||||
lock->vrf = p->cf->iface ? NULL : p->p.vrf;
|
||||
lock->type = OBJLOCK_TCP;
|
||||
lock->hook = bgp_start_locked;
|
||||
lock->data = p;
|
||||
|
|
|
@ -121,6 +121,7 @@ ospf_sk_open(struct ospf_iface *ifa)
|
|||
sk->dport = OSPF_PROTO;
|
||||
sk->saddr = ifa->addr->ip;
|
||||
sk->iface = ifa->iface;
|
||||
sk->vrf = p->p.vrf;
|
||||
|
||||
sk->tos = ifa->cf->tx_tos;
|
||||
sk->priority = ifa->cf->tx_priority;
|
||||
|
@ -204,6 +205,7 @@ ospf_open_vlink_sk(struct ospf_proto *p)
|
|||
sk->type = SK_IP;
|
||||
sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
|
||||
sk->dport = OSPF_PROTO;
|
||||
sk->vrf = p->p.vrf;
|
||||
|
||||
/* FIXME: configurable tos/priority ? */
|
||||
sk->tos = IP_PREC_INTERNET_CONTROL;
|
||||
|
|
|
@ -387,6 +387,7 @@ radv_sk_open(struct radv_iface *ifa)
|
|||
sk->subtype = SK_IPV6;
|
||||
sk->dport = ICMPV6_PROTO;
|
||||
sk->saddr = ifa->addr->ip;
|
||||
sk->vrf = ifa->ra->p.vrf;
|
||||
|
||||
sk->ttl = 255; /* Mandatory for Neighbor Discovery packets */
|
||||
sk->rx_hook = radv_rx_hook;
|
||||
|
|
|
@ -297,7 +297,6 @@ radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_conf
|
|||
ifa->timer = tm_new_init(pool, radv_timer, ifa, 0, 0);
|
||||
|
||||
struct object_lock *lock = olock_new(pool);
|
||||
lock->addr = IPA_NONE;
|
||||
lock->type = OBJLOCK_IP;
|
||||
lock->port = ICMPV6_PROTO;
|
||||
lock->iface = iface;
|
||||
|
|
|
@ -747,6 +747,7 @@ rip_open_socket(struct rip_iface *ifa)
|
|||
sk->dport = ifa->cf->port;
|
||||
sk->iface = ifa->iface;
|
||||
sk->saddr = rip_is_v2(p) ? ifa->iface->addr4->ip : ifa->iface->llv6->ip;
|
||||
sk->vrf = p->p.vrf;
|
||||
|
||||
sk->rx_hook = rip_rx_hook;
|
||||
sk->tx_hook = rip_tx_hook;
|
||||
|
|
|
@ -324,6 +324,7 @@ struct nl_want_attrs {
|
|||
static struct nl_want_attrs ifla_attr_want[BIRD_IFLA_MAX] = {
|
||||
[IFLA_IFNAME] = { 1, 0, 0 },
|
||||
[IFLA_MTU] = { 1, 1, sizeof(u32) },
|
||||
[IFLA_MASTER] = { 1, 1, sizeof(u32) },
|
||||
[IFLA_WIRELESS] = { 1, 0, 0 },
|
||||
};
|
||||
|
||||
|
@ -790,7 +791,7 @@ nl_parse_link(struct nlmsghdr *h, int scan)
|
|||
struct iface f = {};
|
||||
struct iface *ifi;
|
||||
char *name;
|
||||
u32 mtu;
|
||||
u32 mtu, master = 0;
|
||||
uint fl;
|
||||
|
||||
if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(IFLA_RTA(i), ifla_attr_want, a, sizeof(a)))
|
||||
|
@ -813,6 +814,9 @@ nl_parse_link(struct nlmsghdr *h, int scan)
|
|||
name = RTA_DATA(a[IFLA_IFNAME]);
|
||||
mtu = rta_get_u32(a[IFLA_MTU]);
|
||||
|
||||
if (a[IFLA_MASTER])
|
||||
master = rta_get_u32(a[IFLA_MASTER]);
|
||||
|
||||
ifi = if_find_by_index(i->ifi_index);
|
||||
if (!new)
|
||||
{
|
||||
|
@ -832,6 +836,9 @@ nl_parse_link(struct nlmsghdr *h, int scan)
|
|||
f.index = i->ifi_index;
|
||||
f.mtu = mtu;
|
||||
|
||||
f.master_index = master;
|
||||
f.master = if_find_by_index(master);
|
||||
|
||||
fl = i->ifi_flags;
|
||||
if (fl & IFF_UP)
|
||||
f.flags |= IF_ADMIN_UP;
|
||||
|
@ -1091,6 +1098,26 @@ kif_do_scan(struct kif_proto *p UNUSED)
|
|||
else
|
||||
log(L_DEBUG "nl_scan_ifaces: Unknown packet received (type=%d)", h->nlmsg_type);
|
||||
|
||||
/* Re-resolve master interface for slaves */
|
||||
struct iface *i;
|
||||
WALK_LIST(i, iface_list)
|
||||
if (i->master_index)
|
||||
{
|
||||
struct iface f = {
|
||||
.flags = i->flags,
|
||||
.mtu = i->mtu,
|
||||
.index = i->index,
|
||||
.master_index = i->master_index,
|
||||
.master = if_find_by_index(i->master_index)
|
||||
};
|
||||
|
||||
if (f.master != i->master)
|
||||
{
|
||||
memcpy(f.name, i->name, sizeof(f.name));
|
||||
if_update(&f);
|
||||
}
|
||||
}
|
||||
|
||||
nl_request_dump(AF_INET, RTM_GETADDR);
|
||||
while (h = nl_get_scan())
|
||||
if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
|
||||
|
|
|
@ -931,6 +931,18 @@ sk_setup(sock *s)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (s->vrf && !s->iface)
|
||||
{
|
||||
/* Bind socket to associated VRF interface.
|
||||
This is Linux-specific, but so is SO_BINDTODEVICE. */
|
||||
#ifdef SO_BINDTODEVICE
|
||||
struct ifreq ifr = {};
|
||||
strcpy(ifr.ifr_name, s->vrf->name);
|
||||
if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
|
||||
ERR("SO_BINDTODEVICE");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (s->iface)
|
||||
{
|
||||
#ifdef SO_BINDTODEVICE
|
||||
|
|
Loading…
Reference in a new issue