0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-03 15:41:54 +00:00

Merge commit '76dd4730eac6a632ab28ef85d266cbfc0abc89ca' into pim

This commit is contained in:
Ondrej Zajicek (work) 2018-03-03 13:08:38 +01:00
commit c461ab7e90
14 changed files with 720 additions and 8 deletions

View File

@ -17,6 +17,9 @@
#include <libssh/libssh.h>
#endif
struct mif_group;
struct mif;
#ifdef HAVE_LIBSSH
struct ssh_sock {
const char *username; /* (Required) SSH user name */
@ -105,6 +108,7 @@ int sk_join_group(sock *s, ip_addr maddr); /* Join multicast group on sk iface *
int sk_leave_group(sock *s, ip_addr maddr); /* Leave multicast group on sk iface */
int sk_set_router_alert(sock *s, int ra);
int sk_setup_broadcast(sock *s);
int sk_setup_igmp(sock *s, struct mif_group *grp, struct mif *mif);
int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */
int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */
int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd, int setkey);

View File

@ -30,6 +30,7 @@
#include "nest/protocol.h"
#include "nest/cli.h"
#include "lib/resource.h"
#include "lib/socket.h"
#include "lib/string.h"
#include "conf/conf.h"
#include "sysdep/unix/krt.h"
@ -723,6 +724,10 @@ if_init(void)
* Multicast Ifaces
*/
struct mkrt_proto;
void mkrt_register_mif(struct mkrt_proto *p, struct mif *mif);
void mkrt_unregister_mif(struct mkrt_proto *p, struct mif *mif);
static struct mif_group *
mif_get_group(void)
{
@ -754,6 +759,9 @@ mif_get(struct mif_group *grp, struct iface *iface)
grp->mifs[mif->index] = mif;
MIFS_SET(mif, grp->indexes);
if (grp->owner)
mkrt_register_mif((struct mkrt_proto *) grp->owner, mif);
return mif;
}
@ -763,6 +771,9 @@ mif_free(struct mif_group *grp, struct mif *mif)
if (--mif->uc)
return;
if (grp->owner)
mkrt_unregister_mif((struct mkrt_proto *) grp->owner, mif);
node *n;
WALK_LIST_FIRST(n, mif->sockets)
rem_node(n);
@ -773,6 +784,63 @@ mif_free(struct mif_group *grp, struct mif *mif)
mb_free(mif);
}
/*
* Move socket from global list to MIF based lists. These lists are used to
* deliver IGMP messages by mif_forward_igmp().
*/
void
mif_listen_igmp(struct mif_group *grp, struct mif *mif, sock *s)
{
rem_node(&s->n);
add_tail(mif ? &mif->sockets : &grp->sockets, &s->n);
}
/*
* Forward a packet from one socket to another. Emulates the receiving routine.
* Socket is in the same state as if it received the packet itself, but must not
* modify it to preserve it for others.
*/
static void
mif_do_forward(sock *src, sock *dst, int len)
{
if (!dst->rx_hook)
return;
dst->faddr = src->faddr;
dst->laddr = src->laddr;
dst->lifindex = src->lifindex;
dst->rbuf = src->rbuf;
dst->rpos = src->rpos;
dst->rbsize = src->rbsize;
dst->rx_hook(dst, len);
dst->faddr = dst->laddr = IPA_NONE;
dst->lifindex = 0;
dst->rbuf = dst->rpos = NULL;
dst->rbsize = 0;
}
/*
* Forward a packet to all sockets registered for given MIF. It is used to
* deliver IGMP messages from the MRT control socket to IGMP sockets.
*/
void
mif_forward_igmp(struct mif_group *grp, struct mif *mif, sock *src, int len)
{
node *n, *nn;
sock *dst;
WALK_LIST2_DELSAFE(dst, n, nn, grp->sockets, n)
mif_do_forward(src, dst, len);
if (mif)
WALK_LIST2_DELSAFE(dst, n, nn, mif->sockets, n)
mif_do_forward(src, dst, len);
}
/*
* Interface Pattern Lists
*/

View File

@ -56,6 +56,7 @@ struct mif_group {
uint indexes;
uint uc; /* Use count, not implemented */
list sockets; /* Listening global IGMP sockets */
struct proto *owner; /* MKernel responsible for MIFs */
struct mif *mifs[MIFS_MAX];
};

View File

@ -16,6 +16,7 @@
struct ea_list;
struct protocol;
struct proto;
struct channel;
struct rte_src;
struct symbol;
struct filter;
@ -296,7 +297,7 @@ rte *rte_find(net *net, struct rte_src *src);
rte *rte_get_temp(struct rta *);
void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
/* rte_update() moved to protocol.h to avoid dependency conflicts */
int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter);
int rt_examine(struct channel *c, net_addr *a, void (*cb)(struct proto *, void *, rte *), void *data);
rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, struct ea_list **tmpa, linpool *pool, int silent);
void rt_refresh_begin(rtable *t, struct channel *c);
void rt_refresh_end(rtable *t, struct channel *c);

View File

@ -1406,9 +1406,10 @@ rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collec
/* Check rtable for best route to given net whether it would be exported do p */
int
rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
rt_examine(struct channel *c, net_addr *a, void (*cb)(struct proto *, void *, rte *), void *data)
{
net *n = net_find(t, a);
struct proto *p = c->proto;
net *n = net_find(c->table, a);
rte *rt = n ? n->routes : NULL;
if (!rte_is_valid(rt))
@ -1420,7 +1421,11 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
ea_list *tmpa = rte_make_tmp_attrs(rt, rte_update_pool);
int v = p->import_control ? p->import_control(p, &rt, &tmpa, rte_update_pool) : 0;
if (v == RIC_PROCESS)
v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
v = (f_run(c->out_filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
/* Call callback when route is exported */
if (cb && (v > 0))
cb(p, data, rt);
/* Discard temporary rte */
if (rt != n->routes)

View File

@ -558,8 +558,7 @@ radv_check_active(struct radv_proto *p)
if (!radv_trigger_valid(cf))
return 1;
struct channel *c = p->p.main_channel;
return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter);
return rt_examine(p->p.main_channel, &cf->trigger, NULL, NULL);
}
static void

View File

@ -1,3 +1,4 @@
S log.c
S krt.c
S mkrt.c
# io.c is documented under Resources

View File

@ -1,8 +1,8 @@
src := io.c krt.c log.c main.c random.c
src := io.c krt.c log.c main.c mkrt.c random.c
obj := $(src-o-files)
$(all-daemon)
$(cf-local)
$(conf-y-targets): $(s)krt.Y
$(conf-y-targets): $(s)krt.Y $(s)mkrt.Y
src := $(filter-out main.c, $(src))
tests_objs := $(tests_objs) $(src-o-files)

View File

@ -588,6 +588,39 @@ sk_setup_broadcast(sock *s)
return 0;
}
void mif_listen_igmp(struct mif_group *grp, struct mif *mif, sock *s);
/**
* sk_setup_igmp - enable IGMP reception for given socket
* @s: socket
* @grp: MIF group
* @mif: MIF iface, optional
*
* IGMP sockets need to receive all IGMP packets regardless of multicast group.
* The generic multicast API is insufficient for this and both Linux and BSDs
* handle this by passing IGMP packets to multicast routing control socket.
*
* When sk_setup_igmp() is called for a socket, the socket is transfered from
* general socket list to the appropriate MIF socket list and BIRD forwards all
* packets received on a multicast routing control socket to this socket
* internally. That means, all IGMP packets even for groups that no one is
* joined are received here. As a side effect, no packets are received when
* mkernel protocol is down and therefore a multicast control socket is closed.
*
* The socket must have type SK_IP, dport IPPROTO_IGMP and zero rbsize.
*
* Result: 0 for success, -1 for an error.
*/
int
sk_setup_igmp(sock *s, struct mif_group *grp, struct mif *mif)
{
ASSERT((s->type == SK_IP) && (s->dport == IPPROTO_IGMP) && !s->rbsize);
mif_listen_igmp(grp, mif, s);
return 0;
}
/**
* sk_set_ttl - set transmit TTL for given socket
* @s: socket

View File

@ -39,6 +39,7 @@
#include "unix.h"
#include "krt.h"
#include "mkrt.h"
/*
* Debugging
@ -851,6 +852,7 @@ main(int argc, char **argv)
protos_build();
proto_build(&proto_unix_kernel);
proto_build(&proto_unix_iface);
proto_build(&proto_unix_mkrt);
struct config *conf = read_config();

41
sysdep/unix/mkrt.Y Normal file
View File

@ -0,0 +1,41 @@
/*
* BIRD -- UNIX Kernel Multicast Routing Configuration
*
* (c) 2016 Ondrej Hlavaty <aearsis@eideo.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
CF_HDR
#include "sysdep/unix/mkrt.h"
CF_DEFINES
#define THIS_MKRT ((struct mkrt_config *) this_proto)
CF_DECLS
CF_KEYWORDS(MKERNEL)
CF_GRAMMAR
/* Kernel interface protocol */
CF_ADDTO(proto, mkrt_proto '}')
mkrt_proto_start: proto_start MKERNEL { this_proto = mkrt_init_config($1); }
;
mkrt_proto:
mkrt_proto_start proto_name '{'
| mkrt_proto mkrt_proto_item ';'
mkrt_proto_item:
proto_item
| proto_channel { this_proto->net_type = $1->net_type; }
;
CF_CODE
CF_END

503
sysdep/unix/mkrt.c Normal file
View File

@ -0,0 +1,503 @@
/*
* BIRD -- UNIX Kernel Multicast Routing
*
* (c) 2016 Ondrej Hlavaty <aearsis@eideo.cz>
* (c) 2018 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2018 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
/**
* DOC: Kernel Multicast Routing
*
* This protocol is the interface to the kernel part of multicast routing. It
* handles registration of multicast interfaces (MIFs), maintenance of kernel
* Multicast Forwarding Cache (MFC), and reception of incoming IGMP packets.
*
* Multicast forwarding in Linux and BSD kernels is a bit tricky. There must be
* exactly one socket on which setsockopt MRT_INIT is called, then multicast
* forwarding is enabled and kernel multicast routing table is maintained until
* the socket is closed. This MRT control socket is stored in &mrt_sock field.
*
* Multicast forwarding works only on interfaces registered as MIFs, with
* assigned MIF index. While MIFs and MIF indexes are handled by OS-independent
* code in iface.c, actual MIF registration by OS kernel is handled here. The
* MKernel protocol is associated with a MIF group by mkrt_register_mif_group(),
* after that it receive mkrt_register_mif() / mkrt_unregister_mif() calls for
* changes in given MIF group.
*
* Unlike kernel unicast routing API, which is proactive, kernel multicast
* routing API is designed as reactive. Kernel keeps MFC entries for encountered
* (S, G) flows and when a new flow is noticed, BIRD receives cache miss message
* (%IGMPMSG_NOCACHE) from kernel and responds with adding appropriate (S, G)
* MFC entry to the kernel, see mkrt_resolve_mfc(). Therefore, regular route
* notifications handled by mkrt_rt_notify() are not directly translated to
* kernel route updates.
*
* Although there is also support for (*, G) MFC entries in Linux (using
* %MRT_ADD_MFC_PROXY), their behavior is strange and not matching our needs,
* and there is no equivalent in BSD, we do not use them and we manage with
* traditional (S, G) MFC entries.
*
* Finally, the MRT control socket is the only one that receives all IGMP
* packets, even those from non-joined groups. IGMP protocol needs to receive
* these packets, so we forward them internally. To simulate the sane behavior,
* a protocol can open an IGMP socket and use sk_setup_igmp() to register it to
* reception of all IGMP packets. The socket is relinked to internal MIF socket
* list. MKernel protocol then use mif_forward_igmp() to forward packets
* received on the MRT control socket to all sockets on these lists.
*/
#include "nest/bird.h"
#include "nest/iface.h"
#include "lib/socket.h"
#include "unix.h"
#include "mkrt.h"
#include <linux/mroute.h>
/*
* MRT socket options
*/
static inline int
sk_mrt_init4(sock *s)
{
int y = 1;
return setsockopt(s->fd, IPPROTO_IP, MRT_INIT, &y, sizeof(y));
}
static inline int
sk_mrt_done4(sock *s)
{
return setsockopt(s->fd, IPPROTO_IP, MRT_DONE, NULL, 0);
}
static inline int
sk_mrt_add_mif4(sock *s, struct mif *mif)
{
struct vifctl vc = {
.vifc_vifi = mif->index,
.vifc_flags = VIFF_USE_IFINDEX,
.vifc_lcl_ifindex = mif->iface->index,
};
return setsockopt(s->fd, IPPROTO_IP, MRT_ADD_VIF, &vc, sizeof(vc));
}
static inline int
sk_mrt_del_mif4(sock *s, struct mif *mif)
{
struct vifctl vc = {
.vifc_vifi = mif->index,
};
return setsockopt(s->fd, IPPROTO_IP, MRT_DEL_VIF, &vc, sizeof(vc));
}
static inline int
sk_mrt_add_mfc4(sock *s, ip4_addr src, ip4_addr grp, u32 iifs, u32 oifs, int mif_index)
{
struct mfcctl mc = {
.mfcc_origin = ip4_to_in4(src),
.mfcc_mcastgrp = ip4_to_in4(grp),
.mfcc_parent = mif_index,
};
if (BIT32_TEST(&iifs, mif_index) && oifs)
for (int i = 0; i < MIFS_MAX; i++)
if (BIT32_TEST(&oifs, i) && (i != mif_index))
mc.mfcc_ttls[i] = 1;
return setsockopt(s->fd, IPPROTO_IP, MRT_ADD_MFC, &mc, sizeof(mc));
}
static inline int
sk_mrt_del_mfc4(sock *s, ip4_addr src, ip4_addr grp)
{
struct mfcctl mc = {
.mfcc_origin = ip4_to_in4(src),
.mfcc_mcastgrp = ip4_to_in4(grp),
};
return setsockopt(s->fd, IPPROTO_IP, MRT_DEL_MFC, &mc, sizeof(mc));
}
/*
* MIF handling
*/
void
mkrt_register_mif(struct mkrt_proto *p, struct mif *mif)
{
TRACE(D_EVENTS, "Registering interface %s MIF %i", mif->iface->name, mif->index);
if (sk_mrt_add_mif4(p->mrt_sock, mif) < 0)
log(L_ERR "%s: Cannot register interface %s MIF %i: %m",
p->p.name, mif->iface->name, mif->index);
}
void
mkrt_unregister_mif(struct mkrt_proto *p, struct mif *mif)
{
TRACE(D_EVENTS, "Unregistering interface %s MIF %i", mif->iface->name, mif->index);
if (sk_mrt_del_mif4(p->mrt_sock, mif) < 0)
log(L_ERR "%s: Cannot unregister interface %s MIF %i: %m",
p->p.name, mif->iface->name, mif->index);
}
void
mkrt_register_mif_group(struct mkrt_proto *p, struct mif_group *grp)
{
ASSERT(!grp->owner);
grp->owner = &p->p;
WALK_ARRAY(grp->mifs, MIFS_MAX, mif)
if (mif)
mkrt_register_mif(p, mif);
}
void
mkrt_unregister_mif_group(struct mkrt_proto *p, struct mif_group *grp)
{
grp->owner = NULL;
WALK_ARRAY(grp->mifs, MIFS_MAX, mif)
if (mif)
mkrt_unregister_mif(p, mif);
}
/*
* MFC handling
*/
static void
mkrt_init_mfc(void *G)
{
struct mkrt_mfc_group *grp = G;
init_list(&grp->sources);
}
static struct mkrt_mfc_source *
mkrt_get_mfc(struct mkrt_proto *p, ip4_addr source, ip4_addr group)
{
net_addr_mgrp4 n = NET_ADDR_MGRP4(group);
struct mkrt_mfc_group *grp = fib_get(&p->mfc_groups, (net_addr *) &n);
struct mkrt_mfc_source *src;
WALK_LIST(src, grp->sources)
if (ip4_equal(src->addr, source))
return src;
src = mb_allocz(p->p.pool, sizeof(struct mkrt_mfc_source));
src->addr = source;
src->parent = -1;
add_tail(&grp->sources, NODE src);
return src;
}
struct mfc_result {
u32 iifs, oifs;
};
static void
mkrt_resolve_mfc_hook(struct proto *p UNUSED, void *data, rte *rte)
{
struct mfc_result *res = data;
res->iifs = rta_iifs(rte->attrs);
res->oifs = rta_oifs(rte->attrs);
}
/*
* Resolve the MFC miss by adding a MFC entry. If no matching entry in the
* routing table exists, add an empty one to satisfy the kernel.
*/
static void
mkrt_resolve_mfc(struct mkrt_proto *p, ip4_addr src, ip4_addr grp, int mif_index)
{
struct mif *mif = (mif_index < MIFS_MAX) ? p->mif_group->mifs[mif_index] : NULL;
TRACE(D_EVENTS, "MFC miss for (%I4, %I4, %s)", src, grp, mif ? mif->iface->name : "?");
net_addr_mgrp4 n0 = NET_ADDR_MGRP4(grp);
struct mfc_result res = {};
rt_examine(p->p.main_channel, (net_addr *) &n0, mkrt_resolve_mfc_hook, &res);
struct mkrt_mfc_source *mfc = mkrt_get_mfc(p, src, grp);
mfc->iifs = res.iifs;
mfc->oifs = res.oifs;
mfc->parent = mif_index;
TRACE(D_EVENTS, "Adding MFC entry for (%I4, %I4)", src, grp);
if (sk_mrt_add_mfc4(p->mrt_sock, src, grp, mfc->iifs, mfc->oifs, mfc->parent) < 0)
log(L_ERR "%s: Failed to add MFC entry: %m", p->p.name);
}
static void
mkrt_remove_mfc(struct mkrt_proto *p, struct mkrt_mfc_source *src, ip4_addr grp)
{
TRACE(D_EVENTS, "Removing MFC entry for (%I4, %I4)", src->addr, grp);
if (sk_mrt_del_mfc4(p->mrt_sock, src->addr, grp) < 0)
log(L_ERR "%s: Failed to remove MFC entry: %m", p->p.name);
rem_node(NODE src);
mb_free(src);
}
/*
* Because a route in the internal table has changed, all the corresponding MFC
* entries are now wrong. Instead of correcting them, just flush the cache.
*/
static void
mkrt_reset_mfc_group(struct mkrt_proto *p, struct mkrt_mfc_group *grp)
{
ip4_addr group = net4_prefix(grp->n.addr);
struct mkrt_mfc_source *src;
WALK_LIST_FIRST(src, grp->sources)
mkrt_remove_mfc(p, src, group);
}
static void
mkrt_free_mfc_group(struct mkrt_proto *p, struct mkrt_mfc_group *grp)
{
mkrt_reset_mfc_group(p, grp);
fib_delete(&p->mfc_groups, grp);
}
static void
mkrt_rt_notify(struct proto *P, struct channel *c UNUSED, net *net, rte *new, rte *old UNUSED, ea_list *attrs UNUSED)
{
struct mkrt_proto *p = (void *) P;
struct mkrt_mfc_group *grp = fib_find(&p->mfc_groups, net->n.addr);
if (!grp)
return;
/* Drop all MFC entries (possibly along with the state information) for a group */
if (new)
mkrt_reset_mfc_group(p, grp);
else
mkrt_free_mfc_group(p, grp);
}
/*
* On MRT control socket, we receive not only regular IGMP messages but also
* so-called upcalls from the kernel. We must process them here.
*/
void mif_forward_igmp(struct mif_group *grp, struct mif *mif, sock *src, int len);
static int
mkrt_rx_hook(sock *sk, uint len)
{
struct mkrt_proto *p = sk->data;
struct igmpmsg *msg = (void *) sk->rbuf;
u8 igmp_type = * (u8 *) sk_rx_buffer(sk, &len);
switch (igmp_type)
{
case IGMPMSG_NOCACHE:
mkrt_resolve_mfc(p, ip4_from_in4(msg->im_src), ip4_from_in4(msg->im_dst), msg->im_vif);
return 1;
case IGMPMSG_WRONGVIF:
case IGMPMSG_WHOLEPKT:
/* These should not happen unless some PIM-specific MRT options are enabled */
return 1;
default:
// FIXME: Use sk->lifindex or msg->im_vif ?
mif_forward_igmp(p->mif_group, NULL, sk, len);
return 1;
}
}
static void
mkrt_err_hook(sock *sk, int err)
{
struct mkrt_proto *p = sk->data;
log(L_ERR "%s: Socket error: %M", p->p.name, err);
}
static int
mkrt_open_socket(struct mkrt_proto *p)
{
sock *sk = sk_new(p->p.pool);
sk->type = SK_IP;
sk->subtype = SK_IPV4;
sk->dport = IPPROTO_IGMP;
sk->flags = SKF_LADDR_RX;
sk->data = p;
sk->ttl = 1;
sk->rx_hook = mkrt_rx_hook;
sk->err_hook = mkrt_err_hook;
sk->rbsize = 4096;
sk->tbsize = 0;
if (sk_open(sk) < 0)
{
sk_log_error(sk, p->p.name);
goto err;
}
if (sk_mrt_init4(sk) < 0)
{
if (errno == EADDRINUSE)
log(L_ERR "%s: Another multicast daemon is running", p->p.name);
else
log(L_ERR "%s: Cannot enable multicast in kernel: %m", p->p.name);
goto err;
}
p->mrt_sock = sk;
return 1;
err:
rfree(sk);
return 0;
}
static void
mkrt_close_socket(struct mkrt_proto *p)
{
sk_mrt_done4(p->mrt_sock);
rfree(p->mrt_sock);
p->mrt_sock = NULL;
}
/*
* Protocol glue
*/
static struct mkrt_config *mkrt_cf;
static void
mkrt_preconfig(struct protocol *P UNUSED, struct config *c UNUSED)
{
mkrt_cf = NULL;
}
struct proto_config *
mkrt_init_config(int class)
{
if (mkrt_cf)
cf_error("Multicast kernel protocol already defined");
mkrt_cf = (struct mkrt_config *) proto_config_new(&proto_unix_mkrt, class);
return (struct proto_config *) mkrt_cf;
}
void
mkrt_postconfig(struct proto_config *CF)
{
// struct mkrt_config *cf = (void *) CF;
if (EMPTY_LIST(CF->channels))
cf_error("Channel not specified");
}
static struct proto *
mkrt_init(struct proto_config *CF)
{
struct mkrt_proto *p = proto_new(CF);
p->p.main_channel = proto_add_channel(&p->p, proto_cf_main_channel(CF));
p->p.rt_notify = mkrt_rt_notify;
p->mif_group = global_mif_group;
return &p->p;
}
static int
mkrt_start(struct proto *P)
{
struct mkrt_proto *p = (void *) P;
fib_init(&p->mfc_groups, p->p.pool, NET_MGRP4, sizeof(struct mkrt_mfc_group),
OFFSETOF(struct mkrt_mfc_group, n), 6, mkrt_init_mfc);
if (!mkrt_open_socket(p))
return PS_START;
mkrt_register_mif_group(p, p->mif_group);
return PS_UP;
}
static int
mkrt_shutdown(struct proto *P)
{
struct mkrt_proto *p = (void *) P;
if (p->p.proto_state == PS_START)
return PS_DOWN;
mkrt_unregister_mif_group(p, p->mif_group);
mkrt_close_socket(p);
return PS_DOWN;
}
static int
mkrt_reconfigure(struct proto *p, struct proto_config *CF)
{
// struct mkrt_config *o = (void *) p->cf;
// struct mkrt_config *n = (void *) CF;
if (!proto_configure_channel(p, &p->main_channel, proto_cf_main_channel(CF)))
return 0;
return 1;
}
static void
mkrt_dump(struct proto *P)
{
struct mkrt_proto *p = (void *) P;
debug("\t(S,G) entries in MFC in kernel:\n");
FIB_WALK(&p->mfc_groups, struct mkrt_mfc_group, grp)
{
struct mkrt_mfc_source *src;
WALK_LIST(src, grp->sources)
debug("\t\t(%I4, %I4, %d) -> %b %b\n",
src->addr, net4_prefix(grp->n.addr), src->parent, src->iifs, src->oifs);
}
FIB_WALK_END;
}
struct protocol proto_unix_mkrt = {
.name = "MKernel",
.template = "mkernel%d",
.channel_mask = NB_MGRP4,
.proto_size = sizeof(struct mkrt_proto),
.config_size = sizeof(struct mkrt_config),
.preconfig = mkrt_preconfig,
.postconfig = mkrt_postconfig,
.init = mkrt_init,
.start = mkrt_start,
.shutdown = mkrt_shutdown,
.reconfigure = mkrt_reconfigure,
.dump = mkrt_dump,
};

51
sysdep/unix/mkrt.h Normal file
View File

@ -0,0 +1,51 @@
/*
* BIRD -- UNIX Kernel Multicast Routing
*
* (c) 2016 Ondrej Hlavaty <aearsis@eideo.cz>
* (c) 2018 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2018 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#ifndef _BIRD_MKRT_H_
#define _BIRD_MKRT_H_
#include "nest/bird.h"
#include "nest/iface.h"
#include "nest/protocol.h"
#include "nest/route.h"
#include "lib/socket.h"
extern struct protocol proto_unix_mkrt;
struct mkrt_config {
struct proto_config cf;
};
struct mkrt_mfc_group {
list sources; /* List of MFC entries (struct mkrt_mfc_source) */
struct fib_node n;
};
struct mkrt_mfc_source {
node n;
ip4_addr addr;
int parent; /* MIF index of valid incoming iface */
u32 iifs, oifs; /* Values from the multicast route */
};
struct mkrt_proto {
struct proto p;
struct mif_group *mif_group; /* Associated MIF group for multicast routes */
sock *mrt_sock; /* MRT control socket */
struct fib mfc_groups; /* MFC entries/groups managed by protocol */
};
struct proto_config *mkrt_init_config(int class);
#endif

View File

@ -58,6 +58,9 @@ typedef struct sockaddr_bird {
static inline ip_addr ipa_from_in4(struct in_addr a)
{ return ipa_from_u32(ntohl(a.s_addr)); }
static inline ip4_addr ip4_from_in4(struct in_addr a)
{ return ip4_from_u32(ntohl(a.s_addr)); }
static inline ip_addr ipa_from_in6(struct in6_addr a)
{ return ipa_build6(ntohl(a.s6_addr32[0]), ntohl(a.s6_addr32[1]), ntohl(a.s6_addr32[2]), ntohl(a.s6_addr32[3])); }