Commit 46434a3c authored by Ondřej Zajíček's avatar Ondřej Zajíček

Merge commit '7b2c5f3d' into int-new

parents 4ff15a75 7b2c5f3d
Pipeline #27764 failed with stages
in 6 minutes and 25 seconds
......@@ -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); }
;
......
......@@ -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,8 +154,9 @@ 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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment