From 45a8eba9721f8d9b9939a2c916c476eb8be3e78d Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 27 Jan 2017 14:22:47 -0200 Subject: [PATCH] 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 | 177 +++++++++++++++++++++++++++++++++------- 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, 563 insertions(+), 97 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 @@ + + + + + + + + + + + + + + + +