From cfb67a784e77380a5a67b06da3955191b1c752ed Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 27 Jan 2017 18:16:31 -0200 Subject: [PATCH 1/6] lib: remove unnecessary variable Signed-off-by: Renato Westphal --- lib/vrf.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/vrf.c b/lib/vrf.c index ce8ffe75d5..ab7b43b078 100644 --- a/lib/vrf.c +++ b/lib/vrf.c @@ -482,11 +482,9 @@ DEFUN (vrf, { int idx_name = 1; const char *vrfname = argv[idx_name]->arg; - struct vrf *vrfp; - size_t sl; - if ((sl = strlen(vrfname)) > VRF_NAMSIZ) + if (strlen(vrfname) > VRF_NAMSIZ) { vty_out (vty, "%% VRF name %s is invalid: length exceeds " "%d characters%s", From e2a534d557d2d62ec7f69a58a1ae263db214ff52 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 27 Jan 2017 18:18:13 -0200 Subject: [PATCH 2/6] zebra: fix wrong asserts in netlink code These new asserts were causing zebra to abort when trying to install MPLS labeled routes. Signed-off-by: Renato Westphal --- zebra/kernel_netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index fb1015e5d5..058d14481e 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -349,7 +349,7 @@ addattr_l (struct nlmsghdr *n, unsigned int maxlen, int type, if (data) memcpy (RTA_DATA (rta), data, alen); else - assert (len == 0); + assert (alen == 0); n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len); @@ -375,7 +375,7 @@ rta_addattr_l (struct rtattr *rta, unsigned int maxlen, int type, if (data) memcpy (RTA_DATA (subrta), data, alen); else - assert (len == 0); + assert (alen == 0); rta->rta_len = NLMSG_ALIGN (rta->rta_len) + RTA_ALIGN (len); From 64dffe251ab5d1119b151731a22fa6d6cd4e6d50 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 27 Jan 2017 20:01:35 -0200 Subject: [PATCH 3/6] ldpd: release all memory explicitly on exit Signed-off-by: Renato Westphal --- ldpd/ldp_zebra.c | 8 ++++++++ ldpd/ldpd.c | 9 +++++++++ ldpd/ldpd.h | 3 ++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 8e7c6e27f9..79c4f5b377 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -497,3 +497,11 @@ ldp_zebra_init(struct thread_master *master) zclient->redistribute_route_ipv6_add = ldp_zebra_read_route; zclient->redistribute_route_ipv6_del = ldp_zebra_read_route; } + +void +ldp_zebra_destroy(void) +{ + zclient_stop(zclient); + zclient_free(zclient); + zclient = NULL; +} diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 391e013376..c9f4e37eee 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -453,6 +453,15 @@ ldpd_shutdown(void) free(iev_lde); log_info("terminating"); + + vrf_terminate(); + cmd_terminate(); + vty_terminate(); + ldp_zebra_destroy(); + zprivs_terminate(&ldpd_privs); + thread_master_free(master); + closezlog(zlog_default); + exit(0); } diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 4d575597ae..3f6d7ac569 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -694,7 +694,8 @@ int sock_set_ipv6_mcast_loop(int); extern struct thread_master *master; /* ldp_zebra.c */ -void ldp_zebra_init(struct thread_master *); +void ldp_zebra_init(struct thread_master *); +void ldp_zebra_destroy(void); /* compatibility */ #ifndef __OpenBSD__ From be54d7449aebd657e378016a1228ec1b006936cc Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Wed, 1 Feb 2017 13:03:53 -0200 Subject: [PATCH 4/6] ldpd: fix a bug in the explicit-null command Be more clever and update the label of the connected routes just once upon a configuration change. This is not only more efficient but also fixes a bug where no labels were updated when we didn't have any neighbors. Signed-off-by: Renato Westphal --- ldpd/lde.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/ldpd/lde.c b/ldpd/lde.c index 0aa422c23a..91b2b1727f 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -1266,8 +1266,8 @@ lde_change_egress_label(int af, int was_implicit) struct fec *f; struct fec_node *fn; + /* explicitly withdraw all null labels */ RB_FOREACH(ln, nbr_tree, &lde_nbrs) { - /* explicit withdraw */ if (was_implicit) lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL, NULL); @@ -1279,33 +1279,34 @@ lde_change_egress_label(int af, int was_implicit) lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV6NULL, NULL); } + } - /* advertise new label of connected prefixes */ - RB_FOREACH(f, fec_tree, &ft) { - fn = (struct fec_node *)f; - if (fn->local_label > MPLS_LABEL_RESERVED_MAX) + /* update label of connected routes */ + RB_FOREACH(f, fec_tree, &ft) { + fn = (struct fec_node *)f; + if (fn->local_label > MPLS_LABEL_RESERVED_MAX) + continue; + + switch (af) { + case AF_INET: + if (fn->fec.type != FEC_TYPE_IPV4) continue; - - switch (af) { - case AF_INET: - if (fn->fec.type != FEC_TYPE_IPV4) - continue; - break; - case AF_INET6: - if (fn->fec.type != FEC_TYPE_IPV6) - continue; - break; - default: - fatalx("lde_change_egress_label: unknown af"); - } - - fn->local_label = egress_label(fn->fec.type); - lde_send_labelmapping(ln, fn, 0); + break; + case AF_INET6: + if (fn->fec.type != FEC_TYPE_IPV6) + continue; + break; + default: + fatalx("lde_change_egress_label: unknown af"); } + fn->local_label = egress_label(fn->fec.type); + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelmapping(ln, fn, 0); + } + RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, NULL, 0); - } } static int From 28e8294caa010c246bccbff308cb2118b7d52bdb Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Wed, 1 Feb 2017 09:51:54 -0200 Subject: [PATCH 5/6] ldpd: add synchronous IPC channels By default all ldpd interprocess communication is asynchronous (non-blocking socketpairs). Under some circumstances, however, we'll need synchronous IPC as well. Examples: * the lde child process requesting labels to zebra (through the parent process); * apply an access-list on a given IP prefix (ACLs are only available in the parent process). This patch only adds the necessary infrastructure to allow the child processes to make synchronous requests to the parent process. Later patches will make use of this new infrastructure. Signed-off-by: Renato Westphal --- ldpd/lde.c | 16 +++++++++---- ldpd/ldpd.c | 66 ++++++++++++++++++++++++++++++++++++++--------------- ldpd/ldpd.h | 3 +++ ldpd/ldpe.c | 16 +++++++++---- 4 files changed, 72 insertions(+), 29 deletions(-) diff --git a/ldpd/lde.c b/ldpd/lde.c index 91b2b1727f..a28862881d 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -58,7 +58,7 @@ struct ldpd_conf *ldeconf; struct nbr_tree lde_nbrs = RB_INITIALIZER(&lde_nbrs); static struct imsgev *iev_ldpe; -static struct imsgev *iev_main; +static struct imsgev *iev_main, *iev_main_sync; /* Master of threads. */ struct thread_master *master; @@ -133,15 +133,18 @@ lde(const char *user, const char *group) /* setup signal handler */ signal_init(master, array_size(lde_signals), lde_signals); - /* setup pipe and event handler to the parent process */ - if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) + /* setup pipes and event handlers to the parent process */ + if ((iev_main = calloc(1, sizeof(struct imsgev))) == NULL) fatal(NULL); - imsg_init(&iev_main->ibuf, 3); + imsg_init(&iev_main->ibuf, LDPD_FD_ASYNC); iev_main->handler_read = lde_dispatch_parent; iev_main->ev_read = thread_add_read(master, iev_main->handler_read, iev_main, iev_main->ibuf.fd); iev_main->handler_write = ldp_write_handler; - iev_main->ev_write = NULL; + + if ((iev_main_sync = calloc(1, sizeof(struct imsgev))) == NULL) + fatal(NULL); + imsg_init(&iev_main_sync->ibuf, LDPD_FD_SYNC); /* start the LIB garbage collector */ lde_gc_start_timer(); @@ -162,6 +165,8 @@ lde_shutdown(void) close(iev_ldpe->ibuf.fd); msgbuf_clear(&iev_main->ibuf.w); close(iev_main->ibuf.fd); + msgbuf_clear(&iev_main_sync->ibuf.w); + close(iev_main_sync->ibuf.fd); lde_gc_stop_timer(); lde_nbr_clear(); @@ -171,6 +176,7 @@ lde_shutdown(void) free(iev_ldpe); free(iev_main); + free(iev_main_sync); log_info("label decision engine exiting"); exit(0); diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index c9f4e37eee..6fd4251edc 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -42,7 +42,7 @@ #include "qobj.h" static void ldpd_shutdown(void); -static pid_t start_child(enum ldpd_process, char *, int, +static pid_t start_child(enum ldpd_process, char *, int, int, const char *, const char *); static int main_dispatch_ldpe(struct thread *); static int main_dispatch_lde(struct thread *); @@ -77,8 +77,8 @@ DEFINE_QOBJ_TYPE(ldpd_conf) struct ldpd_global global; struct ldpd_conf *ldpd_conf; -static struct imsgev *iev_ldpe; -static struct imsgev *iev_lde; +static struct imsgev *iev_ldpe, *iev_ldpe_sync; +static struct imsgev *iev_lde, *iev_lde_sync; static pid_t ldpe_pid; static pid_t lde_pid; @@ -207,8 +207,8 @@ main(int argc, char *argv[]) { char *saved_argv0; int lflag = 0, eflag = 0; - int pipe_parent2ldpe[2]; - int pipe_parent2lde[2]; + int pipe_parent2ldpe[2], pipe_parent2ldpe_sync[2]; + int pipe_parent2lde[2], pipe_parent2lde_sync[2]; char *p; char *vty_addr = NULL; int vty_port = LDP_VTY_PORT; @@ -347,22 +347,34 @@ main(int argc, char *argv[]) if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2ldpe) == -1) fatal("socketpair"); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, + pipe_parent2ldpe_sync) == -1) + fatal("socketpair"); if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2lde) == -1) fatal("socketpair"); + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, + pipe_parent2lde_sync) == -1) + fatal("socketpair"); sock_set_nonblock(pipe_parent2ldpe[0]); sock_set_cloexec(pipe_parent2ldpe[0]); sock_set_nonblock(pipe_parent2ldpe[1]); sock_set_cloexec(pipe_parent2ldpe[1]); + sock_set_nonblock(pipe_parent2ldpe_sync[0]); + sock_set_cloexec(pipe_parent2ldpe_sync[0]); + sock_set_cloexec(pipe_parent2ldpe_sync[1]); sock_set_nonblock(pipe_parent2lde[0]); sock_set_cloexec(pipe_parent2lde[0]); sock_set_nonblock(pipe_parent2lde[1]); sock_set_cloexec(pipe_parent2lde[1]); + sock_set_nonblock(pipe_parent2lde_sync[0]); + sock_set_cloexec(pipe_parent2lde_sync[0]); + sock_set_cloexec(pipe_parent2lde_sync[1]); /* start children */ lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0, - pipe_parent2lde[1], user, group); + pipe_parent2lde[1], pipe_parent2lde_sync[1], user, group); ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0, - pipe_parent2ldpe[1], user, group); + pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1], user, group); /* drop privileges */ if (user) @@ -378,22 +390,34 @@ main(int argc, char *argv[]) ldp_zebra_init(master); /* setup pipes to children */ - if ((iev_ldpe = malloc(sizeof(struct imsgev))) == NULL || - (iev_lde = malloc(sizeof(struct imsgev))) == NULL) + if ((iev_ldpe = calloc(1, sizeof(struct imsgev))) == NULL || + (iev_ldpe_sync = calloc(1, sizeof(struct imsgev))) == NULL || + (iev_lde = calloc(1, sizeof(struct imsgev))) == NULL || + (iev_lde_sync = calloc(1, sizeof(struct imsgev))) == NULL) fatal(NULL); imsg_init(&iev_ldpe->ibuf, pipe_parent2ldpe[0]); iev_ldpe->handler_read = main_dispatch_ldpe; iev_ldpe->ev_read = thread_add_read(master, iev_ldpe->handler_read, iev_ldpe, iev_ldpe->ibuf.fd); iev_ldpe->handler_write = ldp_write_handler; - iev_ldpe->ev_write = NULL; + + imsg_init(&iev_ldpe_sync->ibuf, pipe_parent2ldpe_sync[0]); + iev_ldpe_sync->handler_read = main_dispatch_ldpe; + iev_ldpe_sync->ev_read = thread_add_read(master, + iev_ldpe_sync->handler_read, iev_ldpe_sync, iev_ldpe_sync->ibuf.fd); + iev_ldpe_sync->handler_write = ldp_write_handler; imsg_init(&iev_lde->ibuf, pipe_parent2lde[0]); iev_lde->handler_read = main_dispatch_lde; iev_lde->ev_read = thread_add_read(master, iev_lde->handler_read, iev_lde, iev_lde->ibuf.fd); iev_lde->handler_write = ldp_write_handler; - iev_lde->ev_write = NULL; + + imsg_init(&iev_lde_sync->ibuf, pipe_parent2lde_sync[0]); + iev_lde_sync->handler_read = main_dispatch_lde; + iev_lde_sync->ev_read = thread_add_read(master, + iev_lde_sync->handler_read, iev_lde_sync, iev_lde_sync->ibuf.fd); + iev_lde_sync->handler_write = ldp_write_handler; if (main_imsg_send_ipc_sockets(&iev_ldpe->ibuf, &iev_lde->ibuf)) fatal("could not establish imsg links"); @@ -466,8 +490,8 @@ ldpd_shutdown(void) } static pid_t -start_child(enum ldpd_process p, char *argv0, int fd, const char *user, - const char *group) +start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync, + const char *user, const char *group) { char *argv[7]; int argc = 0; @@ -479,12 +503,15 @@ start_child(enum ldpd_process p, char *argv0, int fd, const char *user, case 0: break; default: - close(fd); + close(fd_async); + close(fd_sync); return (pid); } - if (dup2(fd, 3) == -1) - fatal("cannot setup imsg fd"); + if (dup2(fd_async, LDPD_FD_ASYNC) == -1) + fatal("cannot setup imsg async fd"); + if (dup2(fd_sync, LDPD_FD_SYNC) == -1) + fatal("cannot setup imsg sync fd"); argv[argc++] = argv0; switch (p) { @@ -702,10 +729,11 @@ main_imsg_compose_both(enum imsg_type type, void *buf, uint16_t len) void imsg_event_add(struct imsgev *iev) { - THREAD_READ_ON(master, iev->ev_read, iev->handler_read, iev, - iev->ibuf.fd); + if (iev->handler_read) + THREAD_READ_ON(master, iev->ev_read, iev->handler_read, iev, + iev->ibuf.fd); - if (iev->ibuf.w.queued) + if (iev->handler_write && iev->ibuf.w.queued) THREAD_WRITE_ON(master, iev->ev_write, iev->handler_write, iev, iev->ibuf.fd); } diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 3f6d7ac569..2c9706cf47 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -33,6 +33,9 @@ #define CONF_FILE "/etc/ldpd.conf" #define LDPD_USER "_ldpd" +#define LDPD_FD_ASYNC 3 +#define LDPD_FD_SYNC 4 + #define LDPD_OPT_VERBOSE 0x00000001 #define LDPD_OPT_VERBOSE2 0x00000002 #define LDPD_OPT_NOACTION 0x00000004 diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 1a60af8f41..236e71f322 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -48,7 +48,7 @@ struct ldpd_conf *leconf; struct ldpd_sysdep sysdep; #endif -static struct imsgev *iev_main; +static struct imsgev *iev_main, *iev_main_sync; static struct imsgev *iev_lde; #ifdef __OpenBSD__ static struct thread *pfkey_ev; @@ -142,15 +142,18 @@ ldpe(const char *user, const char *group) /* setup signal handler */ signal_init(master, array_size(ldpe_signals), ldpe_signals); - /* setup pipe and event handler to the parent process */ - if ((iev_main = malloc(sizeof(struct imsgev))) == NULL) + /* setup pipes and event handlers to the parent process */ + if ((iev_main = calloc(1, sizeof(struct imsgev))) == NULL) fatal(NULL); - imsg_init(&iev_main->ibuf, 3); + imsg_init(&iev_main->ibuf, LDPD_FD_ASYNC); iev_main->handler_read = ldpe_dispatch_main; iev_main->ev_read = thread_add_read(master, iev_main->handler_read, iev_main, iev_main->ibuf.fd); iev_main->handler_write = ldp_write_handler; - iev_main->ev_write = NULL; + + if ((iev_main_sync = calloc(1, sizeof(struct imsgev))) == NULL) + fatal(NULL); + imsg_init(&iev_main_sync->ibuf, LDPD_FD_SYNC); #ifdef __OpenBSD__ if (sysdep.no_pfkey == 0) @@ -191,6 +194,8 @@ ldpe_shutdown(void) msgbuf_write(&iev_main->ibuf.w); msgbuf_clear(&iev_main->ibuf.w); close(iev_main->ibuf.fd); + msgbuf_clear(&iev_main_sync->ibuf.w); + close(iev_main_sync->ibuf.fd); control_cleanup(); config_clear(leconf); @@ -215,6 +220,7 @@ ldpe_shutdown(void) /* clean up */ free(iev_lde); free(iev_main); + free(iev_main_sync); free(pkt_ptr); log_info("ldp engine exiting"); From 45a8eba9721f8d9b9939a2c916c476eb8be3e78d Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 27 Jan 2017 14:22:47 -0200 Subject: [PATCH 6/6] ldpd: introduce advanced filtering capabilities This patch introduces several new configuration commands to ldpd. These commands should allow the operator to define advanced filtering policies for things like label advertisement, label allocation, etc. Signed-off-by: Renato Westphal --- ldpd/hello.c | 12 ++- ldpd/lde.c | 97 ++++++++++++++++++---- ldpd/lde.h | 6 +- ldpd/lde_lib.c | 53 ++++++------ ldpd/ldp_vty.h | 5 +- ldpd/ldp_vty.xml | 67 ++++++++++++++- ldpd/ldp_vty_conf.c | 194 +++++++++++++++++++++++++++++++++++++++++--- ldpd/ldpd.c | 175 ++++++++++++++++++++++++++++++++------- ldpd/ldpd.h | 22 ++++- ldpd/ldpe.c | 11 ++- ldpd/ldpe.h | 1 + lib/filter.c | 8 ++ lib/filter.h | 3 + tools/xml2cli.pl | 4 +- 14 files changed, 562 insertions(+), 96 deletions(-) diff --git a/ldpd/hello.c b/ldpd/hello.c index 95be1d5111..e7935899b7 100644 --- a/ldpd/hello.c +++ b/ldpd/hello.c @@ -265,9 +265,15 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af, } if (!tnbr) { - if (!((flags & F_HELLO_REQ_TARG) && - ((ldp_af_conf_get(leconf, af))->flags & - F_LDPD_AF_THELLO_ACCEPT))) + struct ldpd_af_conf *af_conf; + + if (!(flags & F_HELLO_REQ_TARG)) + return; + af_conf = ldp_af_conf_get(leconf, af); + if (!(af_conf->flags & F_LDPD_AF_THELLO_ACCEPT)) + return; + if (ldpe_acl_check(af_conf->acl_thello_accept_from, af, + src, (af == AF_INET) ? 32 : 128) != FILTER_PERMIT) return; tnbr = tnbr_new(af, src); diff --git a/ldpd/lde.c b/ldpd/lde.c index a28862881d..ff80047207 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -577,11 +577,67 @@ lde_dispatch_parent(struct thread *thread) return (0); } +int +lde_acl_check(char *acl_name, int af, union ldpd_addr *addr, uint8_t prefixlen) +{ + return ldp_acl_request(iev_main_sync, acl_name, af, addr, prefixlen); +} + uint32_t -lde_assign_label(void) +lde_assign_label(struct fec *fec, int connected) { static uint32_t label = MPLS_LABEL_RESERVED_MAX; + /* should we allocate a label for this fec? */ + switch (fec->type) { + case FEC_TYPE_IPV4: + if ((ldeconf->ipv4.flags & F_LDPD_AF_ALLOCHOSTONLY) && + fec->u.ipv4.prefixlen != 32) + return (NO_LABEL); + if (lde_acl_check(ldeconf->ipv4.acl_label_allocate_for, + AF_INET, (union ldpd_addr *)&fec->u.ipv4.prefix, + fec->u.ipv4.prefixlen) != FILTER_PERMIT) + return (NO_LABEL); + break; + case FEC_TYPE_IPV6: + if ((ldeconf->ipv6.flags & F_LDPD_AF_ALLOCHOSTONLY) && + fec->u.ipv6.prefixlen != 128) + return (NO_LABEL); + if (lde_acl_check(ldeconf->ipv6.acl_label_allocate_for, + AF_INET6, (union ldpd_addr *)&fec->u.ipv6.prefix, + fec->u.ipv6.prefixlen) != FILTER_PERMIT) + return (NO_LABEL); + break; + default: + fatalx("lde_assign_label: unexpected fec type"); + break; + } + + if (connected) { + /* choose implicit or explicit-null depending on configuration */ + switch (fec->type) { + case FEC_TYPE_IPV4: + if (!(ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL)) + return (MPLS_LABEL_IMPLNULL); + if (lde_acl_check(ldeconf->ipv4.acl_label_expnull_for, + AF_INET, (union ldpd_addr *)&fec->u.ipv4.prefix, + fec->u.ipv4.prefixlen) != FILTER_PERMIT) + return (MPLS_LABEL_IMPLNULL); + return (MPLS_LABEL_IPV4NULL); + case FEC_TYPE_IPV6: + if (!(ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL)) + return (MPLS_LABEL_IMPLNULL); + if (lde_acl_check(ldeconf->ipv6.acl_label_expnull_for, + AF_INET6, (union ldpd_addr *)&fec->u.ipv6.prefix, + fec->u.ipv6.prefixlen) != FILTER_PERMIT) + return (MPLS_LABEL_IMPLNULL); + return (MPLS_LABEL_IPV6NULL); + default: + fatalx("lde_assign_label: unexpected fec type"); + break; + } + } + /* * TODO: request label to zebra or define a range of labels for ldpd. */ @@ -801,10 +857,24 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) case FEC_TYPE_IPV4: if (!ln->v4_enabled) return; + if (lde_acl_check(ldeconf->ipv4.acl_label_advertise_to, + AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT) + return; + if (lde_acl_check(ldeconf->ipv4.acl_label_advertise_for, + AF_INET, (union ldpd_addr *)&fn->fec.u.ipv4.prefix, + fn->fec.u.ipv4.prefixlen) != FILTER_PERMIT) + return; break; case FEC_TYPE_IPV6: if (!ln->v6_enabled) return; + if (lde_acl_check(ldeconf->ipv6.acl_label_advertise_to, + AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT) + return; + if (lde_acl_check(ldeconf->ipv6.acl_label_advertise_for, + AF_INET6, (union ldpd_addr *)&fn->fec.u.ipv6.prefix, + fn->fec.u.ipv6.prefixlen) != FILTER_PERMIT) + return; break; case FEC_TYPE_PWID: pw = (struct l2vpn_pw *) fn->data; @@ -1266,7 +1336,7 @@ lde_wdraw_del(struct lde_nbr *ln, struct lde_wdraw *lw) } void -lde_change_egress_label(int af, int was_implicit) +lde_change_egress_label(int af) { struct lde_nbr *ln; struct fec *f; @@ -1274,17 +1344,13 @@ lde_change_egress_label(int af, int was_implicit) /* explicitly withdraw all null labels */ RB_FOREACH(ln, nbr_tree, &lde_nbrs) { - if (was_implicit) - lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL, + lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL, NULL); + if (ln->v4_enabled) + lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV4NULL, + NULL); + if (ln->v6_enabled) + lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IPV6NULL, NULL); - else { - if (ln->v4_enabled) - lde_send_labelwithdraw(ln, NULL, - MPLS_LABEL_IPV4NULL, NULL); - if (ln->v6_enabled) - lde_send_labelwithdraw(ln, NULL, - MPLS_LABEL_IPV6NULL, NULL); - } } /* update label of connected routes */ @@ -1306,9 +1372,10 @@ lde_change_egress_label(int af, int was_implicit) fatalx("lde_change_egress_label: unknown af"); } - fn->local_label = egress_label(fn->fec.type); - RB_FOREACH(ln, nbr_tree, &lde_nbrs) - lde_send_labelmapping(ln, fn, 0); + fn->local_label = lde_assign_label(&fn->fec, 1); + if (fn->local_label != NO_LABEL) + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelmapping(ln, fn, 0); } RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_imsg_compose_ldpe(IMSG_MAPPING_ADD_END, ln->peerid, 0, diff --git a/ldpd/lde.h b/ldpd/lde.h index fe90b2c852..7fa5219b12 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -133,7 +133,8 @@ extern struct thread *gc_timer; void lde(const char *, const char *); int lde_imsg_compose_parent(int, pid_t, void *, uint16_t); int lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t); -uint32_t lde_assign_label(void); +int lde_acl_check(char *, int, union ldpd_addr *, uint8_t); +uint32_t lde_assign_label(struct fec *, int); void lde_send_change_klabel(struct fec_node *, struct fec_nh *); void lde_send_delete_klabel(struct fec_node *, struct fec_nh *); void lde_fec2map(struct fec *, struct map *); @@ -154,7 +155,7 @@ struct lde_req *lde_req_add(struct lde_nbr *, struct fec *, int); void lde_req_del(struct lde_nbr *, struct lde_req *, int); struct lde_wdraw *lde_wdraw_add(struct lde_nbr *, struct fec_node *); void lde_wdraw_del(struct lde_nbr *, struct lde_wdraw *); -void lde_change_egress_label(int, int); +void lde_change_egress_label(int); struct lde_addr *lde_address_find(struct lde_nbr *, int, union ldpd_addr *); @@ -169,7 +170,6 @@ void fec_snap(struct lde_nbr *); void fec_tree_clear(void); struct fec_nh *fec_nh_find(struct fec_node *, int, union ldpd_addr *, ifindex_t, uint8_t); -uint32_t egress_label(enum fec_type); void lde_kernel_insert(struct fec *, int, union ldpd_addr *, ifindex_t, uint8_t, int, void *); void lde_kernel_remove(struct fec *, int, union ldpd_addr *, diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index df65edad1a..7a4cb760f1 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -305,25 +305,6 @@ fec_nh_del(struct fec_nh *fnh) free(fnh); } -uint32_t -egress_label(enum fec_type fec_type) -{ - switch (fec_type) { - case FEC_TYPE_IPV4: - if (ldeconf->ipv4.flags & F_LDPD_AF_EXPNULL) - return (MPLS_LABEL_IPV4NULL); - break; - case FEC_TYPE_IPV6: - if (ldeconf->ipv6.flags & F_LDPD_AF_EXPNULL) - return (MPLS_LABEL_IPV6NULL); - break; - default: - fatalx("egress_label: unexpected fec type"); - } - - return (MPLS_LABEL_IMPLNULL); -} - void lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, ifindex_t ifindex, uint8_t priority, int connected, void *data) @@ -347,14 +328,12 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop, fn->data = data; if (fn->local_label == NO_LABEL) { - if (connected) - fn->local_label = egress_label(fn->fec.type); - else - fn->local_label = lde_assign_label(); + fn->local_label = lde_assign_label(&fn->fec, connected); /* FEC.1: perform lsr label distribution procedure */ - RB_FOREACH(ln, nbr_tree, &lde_nbrs) - lde_send_labelmapping(ln, fn, 1); + if (fn->local_label != NO_LABEL) + RB_FOREACH(ln, nbr_tree, &lde_nbrs) + lde_send_labelmapping(ln, fn, 1); } fnh = fec_nh_add(fn, af, nexthop, ifindex, priority); @@ -446,6 +425,30 @@ lde_check_mapping(struct map *map, struct lde_nbr *ln) int msgsource = 0; lde_map2fec(map, ln->id, &fec); + + switch (fec.type) { + case FEC_TYPE_IPV4: + if (lde_acl_check(ldeconf->ipv4.acl_label_accept_from, + AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT) + return; + if (lde_acl_check(ldeconf->ipv4.acl_label_accept_for, + AF_INET, (union ldpd_addr *)&fec.u.ipv4.prefix, + fec.u.ipv4.prefixlen) != FILTER_PERMIT) + return; + break; + case FEC_TYPE_IPV6: + if (lde_acl_check(ldeconf->ipv6.acl_label_accept_from, + AF_INET, (union ldpd_addr *)&ln->id, 32) != FILTER_PERMIT) + return; + if (lde_acl_check(ldeconf->ipv6.acl_label_accept_for, + AF_INET6, (union ldpd_addr *)&fec.u.ipv6.prefix, + fec.u.ipv6.prefixlen) != FILTER_PERMIT) + return; + break; + default: + break; + } + fn = (struct fec_node *)fec_find(&ft, &fec); if (fn == NULL) fn = fec_add(&fec); diff --git a/ldpd/ldp_vty.h b/ldpd/ldp_vty.h index 735554badf..b0dc291434 100644 --- a/ldpd/ldp_vty.h +++ b/ldpd/ldp_vty.h @@ -47,7 +47,10 @@ int ldp_vty_session_holdtime(struct vty *, struct vty_arg *[]); int ldp_vty_interface(struct vty *, struct vty_arg *[]); int ldp_vty_trans_addr(struct vty *, struct vty_arg *[]); int ldp_vty_neighbor_targeted(struct vty *, struct vty_arg *[]); -int ldp_vty_explicit_null(struct vty *, struct vty_arg *[]); +int ldp_vty_label_advertise(struct vty *, struct vty_arg *[]); +int ldp_vty_label_allocate(struct vty *, struct vty_arg *[]); +int ldp_vty_label_expnull(struct vty *, struct vty_arg *[]); +int ldp_vty_label_accept(struct vty *, struct vty_arg *[]); int ldp_vty_ttl_security(struct vty *, struct vty_arg *[]); int ldp_vty_router_id(struct vty *, struct vty_arg *[]); int ldp_vty_ds_cisco_interop(struct vty *, struct vty_arg *[]); diff --git a/ldpd/ldp_vty.xml b/ldpd/ldp_vty.xml index 794f063c4d..966b634c27 100644 --- a/ldpd/ldp_vty.xml +++ b/ldpd/ldp_vty.xml @@ -30,7 +30,48 @@ + + + + + + + + + + + + + + + +