diff options
| -rw-r--r-- | ldpd/hello.c | 12 | ||||
| -rw-r--r-- | ldpd/lde.c | 97 | ||||
| -rw-r--r-- | ldpd/lde.h | 6 | ||||
| -rw-r--r-- | ldpd/lde_lib.c | 53 | ||||
| -rw-r--r-- | ldpd/ldp_vty.h | 5 | ||||
| -rw-r--r-- | ldpd/ldp_vty.xml | 67 | ||||
| -rw-r--r-- | ldpd/ldp_vty_conf.c | 194 | ||||
| -rw-r--r-- | ldpd/ldpd.c | 177 | ||||
| -rw-r--r-- | ldpd/ldpd.h | 22 | ||||
| -rw-r--r-- | ldpd/ldpe.c | 11 | ||||
| -rw-r--r-- | ldpd/ldpe.h | 1 | ||||
| -rw-r--r-- | lib/filter.c | 8 | ||||
| -rw-r--r-- | lib/filter.h | 3 | ||||
| -rwxr-xr-x | 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 @@ <option name="sent" help="Sent messages"/> </options> + <!-- ACL --> + <options name="acl"> + <option input="acl_range" help="IP access-list number"/> + <option input="acl_expanded_range" help="IP access-list number (expanded range)"/> + <option input="word" help="IP access-list name"/> + </options> + <!-- shared subtrees --> + <subtree name="label_local_acls"> + <option name="to" help="IP Access-list specifying controls on LDP Peers"> + <select options="acl" arg="to_acl" function="inherited"> + <option name="for" help="IP access-list for destination prefixes"> + <select options="acl" arg="for_acl" function="inherited"/> + </option> + </select> + </option> + <option name="for" help="IP access-list for destination prefixes"> + <select options="acl" arg="for_acl" function="inherited"> + <option name="to" help="IP Access-list specifying controls on LDP Peers"> + <select options="acl" arg="to_acl" function="inherited"/> + </option> + </select> + </option> + </subtree> + + <subtree name="label_remote_acls"> + <option name="from" help="Neighbor from whom to accept label advertisement"> + <select options="acl" arg="from_acl" function="inherited"> + <option name="for" help="IP access-list for destination prefixes"> + <select options="acl" arg="for_acl" function="inherited"/> + </option> + </select> + </option> + <option name="for" help="IP access-list for destination prefixes"> + <select options="acl" arg="for_acl" function="inherited"> + <option name="from" help="Neighbor from whom to accept label advertisement"> + <select options="acl" arg="from_acl" function="inherited"/> + </option> + </select> + </option> + </subtree> + <subtree name="discovery_link"> <option name="discovery" help="Configure discovery parameters"> <option name="hello" arg="hello_type" help="LDP Link Hellos"> @@ -70,13 +111,33 @@ <include subtree="discovery_targeted"/> <option name="discovery" help="Configure discovery parameters"> <option name="targeted-hello" arg="hello_type" help="LDP Targeted Hellos"> - <option name="accept" help="Accept and respond to targeted hellos" function="ldp_vty_targeted_hello_accept"/> + <option name="accept" help="Accept and respond to targeted hellos" function="ldp_vty_targeted_hello_accept"> + <option name="from" help="Access list to specify acceptable targeted hello source"> + <select options="acl" arg="from_acl" function="inherited"/> + </option> + </option> </option> </option> <option name="label" help="Configure label control and policies"> <option name="local" help="Configure local label control and policies"> - <option name="advertise" help="Configure outbound label advertisement control"> - <option name="explicit-null" help="Configure explicit-null advertisement" function="ldp_vty_explicit_null"/> + <option name="advertise" help="Configure outbound label advertisement control" function="ldp_vty_label_advertise"> + <include subtree="label_local_acls"/> + <option name="explicit-null" help="Configure explicit-null advertisement" function="ldp_vty_label_expnull"> + <option name="for" help="IP access-list for destination prefixes"> + <select options="acl" arg="for_acl" function="inherited"/> + </option> + </option> + </option> + <option name="allocate" help="Configure label allocation control"> + <option name="for" help="IP access-list"> + <select options="acl" arg="for_acl" function="ldp_vty_label_allocate"/> + </option> + <option name="host-routes" arg="host-routes" help="allocate local label for host routes only" function="ldp_vty_label_allocate"/> + </option> + </option> + <option name="remote" help="Configure remote/peer label control and policies"> + <option name="accept" help="Configure inbound label acceptance control" function="ldp_vty_label_accept"> + <include subtree="label_remote_acls"/> </option> </option> </option> diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c index e408abb091..792f8c8d1b 100644 --- a/ldpd/ldp_vty_conf.c +++ b/ldpd/ldp_vty_conf.c @@ -182,9 +182,13 @@ ldp_af_config_write(struct vty *vty, int af, struct ldpd_conf *conf, vty_out(vty, " discovery hello interval %u%s", af_conf->lhello_interval, VTY_NEWLINE); - if (af_conf->flags & F_LDPD_AF_THELLO_ACCEPT) - vty_out(vty, " discovery targeted-hello accept%s", - VTY_NEWLINE); + if (af_conf->flags & F_LDPD_AF_THELLO_ACCEPT) { + vty_out(vty, " discovery targeted-hello accept"); + if (af_conf->acl_thello_accept_from[0] != '\0') + vty_out(vty, " from %s", + af_conf->acl_thello_accept_from); + vty_out(vty, "%s", VTY_NEWLINE); + } if (af_conf->thello_holdtime != TARGETED_DFLT_HOLDTIME && af_conf->thello_holdtime != 0) @@ -202,9 +206,48 @@ ldp_af_config_write(struct vty *vty, int af, struct ldpd_conf *conf, vty_out(vty, " ! Incomplete config, specify a discovery " "transport-address%s", VTY_NEWLINE); - if (af_conf->flags & F_LDPD_AF_EXPNULL) - vty_out(vty, " label local advertise explicit-null%s", - VTY_NEWLINE); + if ((af_conf->flags & F_LDPD_AF_ALLOCHOSTONLY) || + af_conf->acl_label_allocate_for[0] != '\0') { + vty_out(vty, " label local allocate"); + if (af_conf->flags & F_LDPD_AF_ALLOCHOSTONLY) + vty_out(vty, " host-routes"); + else + vty_out(vty, " for %s", + af_conf->acl_label_allocate_for); + vty_out(vty, "%s", VTY_NEWLINE); + } + + if (af_conf->acl_label_advertise_for[0] != '\0' || + af_conf->acl_label_advertise_to[0] != '\0') { + vty_out(vty, " label local advertise"); + if (af_conf->acl_label_advertise_to[0] != '\0') + vty_out(vty, " to %s", + af_conf->acl_label_advertise_to); + if (af_conf->acl_label_advertise_for[0] != '\0') + vty_out(vty, " for %s", + af_conf->acl_label_advertise_for); + vty_out(vty, "%s", VTY_NEWLINE); + } + + if (af_conf->flags & F_LDPD_AF_EXPNULL) { + vty_out(vty, " label local advertise explicit-null"); + if (af_conf->acl_label_expnull_for[0] != '\0') + vty_out(vty, " for %s", + af_conf->acl_label_expnull_for); + vty_out(vty, "%s", VTY_NEWLINE); + } + + if (af_conf->acl_label_accept_for[0] != '\0' || + af_conf->acl_label_accept_from[0] != '\0') { + vty_out(vty, " label remote accept"); + if (af_conf->acl_label_accept_from[0] != '\0') + vty_out(vty, " from %s", + af_conf->acl_label_accept_from); + if (af_conf->acl_label_accept_for[0] != '\0') + vty_out(vty, " for %s", + af_conf->acl_label_accept_for); + vty_out(vty, "%s", VTY_NEWLINE); + } if (af_conf->flags & F_LDPD_AF_NO_GTSM) vty_out(vty, " ttl-security disable%s", VTY_NEWLINE); @@ -681,19 +724,28 @@ ldp_vty_targeted_hello_accept(struct vty *vty, struct vty_arg *args[]) struct ldpd_conf *vty_conf; struct ldpd_af_conf *af_conf; int af; + const char *acl_from_str; int disable; vty_conf = ldp_dup_config(ldpd_conf); disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + acl_from_str = vty_get_arg_value(args, "from_acl"); af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); - if (disable) + if (disable) { af_conf->flags &= ~F_LDPD_AF_THELLO_ACCEPT; - else + af_conf->acl_thello_accept_from[0] = '\0'; + } else { af_conf->flags |= F_LDPD_AF_THELLO_ACCEPT; + if (acl_from_str) + strlcpy(af_conf->acl_thello_accept_from, acl_from_str, + sizeof(af_conf->acl_thello_accept_from)); + else + af_conf->acl_thello_accept_from[0] = '\0'; + } ldp_reload(vty_conf); @@ -978,23 +1030,143 @@ cancel: } int -ldp_vty_explicit_null(struct vty *vty, struct vty_arg *args[]) +ldp_vty_label_advertise(struct vty *vty, struct vty_arg *args[]) { struct ldpd_conf *vty_conf; struct ldpd_af_conf *af_conf; int af; + const char *acl_to_str; + const char *acl_for_str; int disable; disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + acl_to_str = vty_get_arg_value(args, "to_acl"); + acl_for_str = vty_get_arg_value(args, "for_acl"); vty_conf = ldp_dup_config(ldpd_conf); af = ldp_vty_get_af(vty); af_conf = ldp_af_conf_get(vty_conf, af); - if (disable) + if (disable) { + af_conf->acl_label_advertise_to[0] = '\0'; + af_conf->acl_label_advertise_for[0] = '\0'; + } else { + if (acl_to_str) + strlcpy(af_conf->acl_label_advertise_to, acl_to_str, + sizeof(af_conf->acl_label_advertise_to)); + else + af_conf->acl_label_advertise_to[0] = '\0'; + if (acl_for_str) + strlcpy(af_conf->acl_label_advertise_for, acl_for_str, + sizeof(af_conf->acl_label_advertise_for)); + else + af_conf->acl_label_advertise_for[0] = '\0'; + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_label_allocate(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct ldpd_af_conf *af_conf; + int af; + const char *acl_for_str; + const char *host_routes_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + acl_for_str = vty_get_arg_value(args, "for_acl"); + host_routes_str = vty_get_arg_value(args, "host-routes"); + + vty_conf = ldp_dup_config(ldpd_conf); + af = ldp_vty_get_af(vty); + af_conf = ldp_af_conf_get(vty_conf, af); + + af_conf->flags &= ~F_LDPD_AF_ALLOCHOSTONLY; + af_conf->acl_label_allocate_for[0] = '\0'; + if (!disable) { + if (host_routes_str) + af_conf->flags |= F_LDPD_AF_ALLOCHOSTONLY; + else + strlcpy(af_conf->acl_label_allocate_for, acl_for_str, + sizeof(af_conf->acl_label_allocate_for)); + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_label_expnull(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct ldpd_af_conf *af_conf; + int af; + const char *acl_for_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + acl_for_str = vty_get_arg_value(args, "for_acl"); + + vty_conf = ldp_dup_config(ldpd_conf); + af = ldp_vty_get_af(vty); + af_conf = ldp_af_conf_get(vty_conf, af); + + if (disable) { af_conf->flags &= ~F_LDPD_AF_EXPNULL; - else + af_conf->acl_label_expnull_for[0] = '\0'; + } else { af_conf->flags |= F_LDPD_AF_EXPNULL; + if (acl_for_str) + strlcpy(af_conf->acl_label_expnull_for, acl_for_str, + sizeof(af_conf->acl_label_expnull_for)); + else + af_conf->acl_label_expnull_for[0] = '\0'; + } + + ldp_reload(vty_conf); + + return (CMD_SUCCESS); +} + +int +ldp_vty_label_accept(struct vty *vty, struct vty_arg *args[]) +{ + struct ldpd_conf *vty_conf; + struct ldpd_af_conf *af_conf; + int af; + const char *acl_from_str; + const char *acl_for_str; + int disable; + + disable = (vty_get_arg_value(args, "no")) ? 1 : 0; + acl_from_str = vty_get_arg_value(args, "from_acl"); + acl_for_str = vty_get_arg_value(args, "for_acl"); + + vty_conf = ldp_dup_config(ldpd_conf); + af = ldp_vty_get_af(vty); + af_conf = ldp_af_conf_get(vty_conf, af); + + if (disable) { + af_conf->acl_label_accept_from[0] = '\0'; + af_conf->acl_label_accept_for[0] = '\0'; + } else { + if (acl_from_str) + strlcpy(af_conf->acl_label_accept_from, acl_from_str, + sizeof(af_conf->acl_label_accept_from)); + else + af_conf->acl_label_accept_from[0] = '\0'; + if (acl_for_str) + strlcpy(af_conf->acl_label_accept_for, acl_for_str, + sizeof(af_conf->acl_label_accept_for)); + else + af_conf->acl_label_accept_for[0] = '\0'; + } ldp_reload(vty_conf); diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 6fd4251edc..76eb66d926 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -39,6 +39,7 @@ #include "sigevent.h" #include "zclient.h" #include "vrf.h" +#include "filter.h" #include "qobj.h" static void ldpd_shutdown(void); @@ -326,6 +327,7 @@ main(int argc, char *argv[]) vty_config_lockless (); vty_init(master); vrf_init(); + access_list_init (); ldp_vty_init(); ldp_vty_if_init(); @@ -479,6 +481,7 @@ ldpd_shutdown(void) log_info("terminating"); vrf_terminate(); + access_list_reset(); cmd_terminate(); vty_terminate(); ldp_zebra_destroy(); @@ -572,6 +575,12 @@ main_dispatch_ldpe(struct thread *thread) af = imsg.hdr.pid; main_imsg_send_net_sockets(af); break; + case IMSG_ACL_CHECK: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct acl_check)) + fatalx("IMSG_ACL_CHECK imsg with wrong len"); + ldp_acl_reply(iev, (struct acl_check *)imsg.data); + break; default: log_debug("%s: error handling imsg %d", __func__, imsg.hdr.type); @@ -653,6 +662,12 @@ main_dispatch_lde(struct thread *thread) log_warnx("%s: error unsetting pseudowire", __func__); break; + case IMSG_ACL_CHECK: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct acl_check)) + fatalx("IMSG_ACL_CHECK imsg with wrong len"); + ldp_acl_reply(iev, (struct acl_check *)imsg.data); + break; default: log_debug("%s: error handling imsg %d", __func__, imsg.hdr.type); @@ -831,6 +846,70 @@ main_imsg_send_net_socket(int af, enum socket_type type) sizeof(type)); } +int +ldp_acl_request(struct imsgev *iev, char *acl_name, int af, + union ldpd_addr *addr, uint8_t prefixlen) +{ + struct imsg imsg; + ssize_t n; + struct acl_check acl_check; + + if (acl_name[0] == '\0') + return FILTER_PERMIT; + + /* build request */ + strlcpy(acl_check.acl, acl_name, sizeof(acl_check.acl)); + acl_check.af = af; + acl_check.addr = *addr; + acl_check.prefixlen = prefixlen; + + /* send (blocking) */ + imsg_compose_event(iev, IMSG_ACL_CHECK, 0, 0, -1, &acl_check, + sizeof(acl_check)); + imsg_flush(&iev->ibuf); + + /* receive (blocking) and parse result */ + if ((n = imsg_read(&iev->ibuf)) == -1) + fatal("imsg_read error"); + if ((n = imsg_get(&iev->ibuf, &imsg)) == -1) + fatal("imsg_get"); + if (imsg.hdr.type != IMSG_ACL_CHECK || + imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(int)) + fatalx("ldp_acl_request: invalid response"); + + return (*((int *)imsg.data)); +} + +void +ldp_acl_reply(struct imsgev *iev, struct acl_check *acl_check) +{ + struct access_list *alist; + struct prefix prefix; + int result; + + alist = access_list_lookup(family2afi(acl_check->af), acl_check->acl); + if (alist == NULL) + result = FILTER_DENY; + else { + prefix.family = acl_check->af; + switch (prefix.family) { + case AF_INET: + prefix.u.prefix4 = acl_check->addr.v4; + break; + case AF_INET6: + prefix.u.prefix6 = acl_check->addr.v6; + break; + default: + fatalx("ldp_acl_reply: unknown af"); + } + prefix.prefixlen = acl_check->prefixlen; + result = access_list_apply(alist, &prefix); + } + + imsg_compose_event(iev, IMSG_ACL_CHECK, 0, 0, -1, &result, + sizeof(result)); +} + struct ldpd_af_conf * ldp_af_conf_get(struct ldpd_conf *xconf, int af) { @@ -1177,8 +1256,7 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf) /* change of router-id requires resetting all neighborships */ if (conf->rtr_id.s_addr != xconf->rtr_id.s_addr) { if (ldpd_process == PROC_LDP_ENGINE) { - ldpe_reset_nbrs(AF_INET); - ldpe_reset_nbrs(AF_INET6); + ldpe_reset_nbrs(AF_UNSPEC); if (conf->rtr_id.s_addr == INADDR_ANY || xconf->rtr_id.s_addr == INADDR_ANY) { if_update_all(AF_UNSPEC); @@ -1211,61 +1289,98 @@ merge_global(struct ldpd_conf *conf, struct ldpd_conf *xconf) static void merge_af(int af, struct ldpd_af_conf *af_conf, struct ldpd_af_conf *xa) { - int egress_label_changed = 0; - int update_sockets = 0; - + int stop_init_backoff = 0; + int remove_dynamic_tnbrs = 0; + int change_egress_label = 0; + int reset_nbrs_ipv4 = 0; + int reset_nbrs = 0; + int update_sockets = 0; + + /* update timers */ if (af_conf->keepalive != xa->keepalive) { af_conf->keepalive = xa->keepalive; - if (ldpd_process == PROC_LDP_ENGINE) - ldpe_stop_init_backoff(af); + stop_init_backoff = 1; } - af_conf->lhello_holdtime = xa->lhello_holdtime; af_conf->lhello_interval = xa->lhello_interval; af_conf->thello_holdtime = xa->thello_holdtime; af_conf->thello_interval = xa->thello_interval; /* update flags */ - if (ldpd_process == PROC_LDP_ENGINE && - (af_conf->flags & F_LDPD_AF_THELLO_ACCEPT) && + if ((af_conf->flags & F_LDPD_AF_THELLO_ACCEPT) && !(xa->flags & F_LDPD_AF_THELLO_ACCEPT)) - ldpe_remove_dynamic_tnbrs(af); - + remove_dynamic_tnbrs = 1; if ((af_conf->flags & F_LDPD_AF_NO_GTSM) != (xa->flags & F_LDPD_AF_NO_GTSM)) { if (af == AF_INET6) /* need to set/unset IPV6_MINHOPCOUNT */ update_sockets = 1; - else if (ldpd_process == PROC_LDP_ENGINE) + else /* for LDPv4 just resetting the neighbors is enough */ - ldpe_reset_nbrs(af); + reset_nbrs_ipv4 = 1; } - if ((af_conf->flags & F_LDPD_AF_EXPNULL) != (xa->flags & F_LDPD_AF_EXPNULL)) - egress_label_changed = 1; - + change_egress_label = 1; af_conf->flags = xa->flags; - if (egress_label_changed) { - switch (ldpd_process) { - case PROC_LDE_ENGINE: - lde_change_egress_label(af, af_conf->flags & - F_LDPD_AF_EXPNULL); - break; - default: - break; - } - } - + /* update the transport address */ if (ldp_addrcmp(af, &af_conf->trans_addr, &xa->trans_addr)) { af_conf->trans_addr = xa->trans_addr; update_sockets = 1; } - if (ldpd_process == PROC_MAIN && iev_ldpe && update_sockets) - imsg_compose_event(iev_ldpe, IMSG_CLOSE_SOCKETS, af, 0, -1, - NULL, 0); + /* update ACLs */ + if (strcmp(af_conf->acl_label_advertise_to, + xa->acl_label_advertise_to) || + strcmp(af_conf->acl_label_advertise_for, + xa->acl_label_advertise_for) || + strcmp(af_conf->acl_label_accept_from, + xa->acl_label_accept_from) || + strcmp(af_conf->acl_label_accept_for, + xa->acl_label_accept_for)) + reset_nbrs = 1; + if (strcmp(af_conf->acl_thello_accept_from, xa->acl_thello_accept_from)) + remove_dynamic_tnbrs = 1; + if (strcmp(af_conf->acl_label_expnull_for, xa->acl_label_expnull_for)) + change_egress_label = 1; + strlcpy(af_conf->acl_thello_accept_from, xa->acl_thello_accept_from, + sizeof(af_conf->acl_thello_accept_from)); + strlcpy(af_conf->acl_label_allocate_for, xa->acl_label_allocate_for, + sizeof(af_conf->acl_label_allocate_for)); + strlcpy(af_conf->acl_label_advertise_to, xa->acl_label_advertise_to, + sizeof(af_conf->acl_label_advertise_to)); + strlcpy(af_conf->acl_label_advertise_for, xa->acl_label_advertise_for, + sizeof(af_conf->acl_label_advertise_for)); + strlcpy(af_conf->acl_label_accept_from, xa->acl_label_accept_from, + sizeof(af_conf->acl_label_accept_from)); + strlcpy(af_conf->acl_label_accept_for, xa->acl_label_accept_for, + sizeof(af_conf->acl_label_accept_for)); + strlcpy(af_conf->acl_label_expnull_for, xa->acl_label_expnull_for, + sizeof(af_conf->acl_label_expnull_for)); + + /* apply the new configuration */ + switch (ldpd_process) { + case PROC_LDE_ENGINE: + if (change_egress_label) + lde_change_egress_label(af); + break; + case PROC_LDP_ENGINE: + if (stop_init_backoff) + ldpe_stop_init_backoff(af); + if (remove_dynamic_tnbrs) + ldpe_remove_dynamic_tnbrs(af); + if (reset_nbrs) + ldpe_reset_nbrs(AF_UNSPEC); + else if (reset_nbrs_ipv4) + ldpe_reset_nbrs(AF_INET); + break; + case PROC_MAIN: + if (update_sockets && iev_ldpe) + imsg_compose_event(iev_ldpe, IMSG_CLOSE_SOCKETS, af, + 0, -1, NULL, 0); + break; + } } static void diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 2c9706cf47..506891ff07 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -27,6 +27,7 @@ #include "imsg.h" #include "thread.h" #include "qobj.h" +#include "filter.h" #include "ldp.h" @@ -138,7 +139,8 @@ enum imsg_type { IMSG_RECONF_L2VPN_IPW, IMSG_RECONF_END, IMSG_DEBUG_UPDATE, - IMSG_LOG + IMSG_LOG, + IMSG_ACL_CHECK }; union ldpd_addr { @@ -411,12 +413,20 @@ struct ldpd_af_conf { uint16_t thello_holdtime; uint16_t thello_interval; union ldpd_addr trans_addr; + char acl_thello_accept_from[ACL_NAMSIZ]; + char acl_label_allocate_for[ACL_NAMSIZ]; + char acl_label_advertise_to[ACL_NAMSIZ]; + char acl_label_advertise_for[ACL_NAMSIZ]; + char acl_label_expnull_for[ACL_NAMSIZ]; + char acl_label_accept_from[ACL_NAMSIZ]; + char acl_label_accept_for[ACL_NAMSIZ]; int flags; }; #define F_LDPD_AF_ENABLED 0x0001 #define F_LDPD_AF_THELLO_ACCEPT 0x0002 #define F_LDPD_AF_EXPNULL 0x0004 #define F_LDPD_AF_NO_GTSM 0x0008 +#define F_LDPD_AF_ALLOCHOSTONLY 0x0010 struct ldpd_conf { struct in_addr rtr_id; @@ -500,6 +510,13 @@ struct kif { int mtu; }; +struct acl_check { + char acl[ACL_NAMSIZ]; + int af; + union ldpd_addr addr; + uint8_t prefixlen; +}; + /* control data structures */ struct ctl_iface { int af; @@ -630,6 +647,9 @@ void evbuf_event_add(struct evbuf *); void evbuf_init(struct evbuf *, int, int (*)(struct thread *), void *); void evbuf_clear(struct evbuf *); +int ldp_acl_request(struct imsgev *, char *, int, + union ldpd_addr *, uint8_t); +void ldp_acl_reply(struct imsgev *, struct acl_check *); struct ldpd_af_conf *ldp_af_conf_get(struct ldpd_conf *, int); struct ldpd_af_global *ldp_af_global_get(struct ldpd_global *, int); int ldp_is_dual_stack(struct ldpd_conf *); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 236e71f322..0b441c1813 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -408,8 +408,7 @@ ldpe_dispatch_main(struct thread *thread) memcpy(&global.rtr_id, imsg.data, sizeof(global.rtr_id)); if (leconf->rtr_id.s_addr == INADDR_ANY) { - ldpe_reset_nbrs(AF_INET); - ldpe_reset_nbrs(AF_INET6); + ldpe_reset_nbrs(AF_UNSPEC); } if_update_all(AF_UNSPEC); tnbr_update_all(AF_UNSPEC); @@ -722,13 +721,19 @@ ldpe_close_sockets(int af) } } +int +ldpe_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); +} + void ldpe_reset_nbrs(int af) { struct nbr *nbr; RB_FOREACH(nbr, nbr_id_head, &nbrs_by_id) { - if (nbr->af == af) + if (af == AF_UNSPEC || nbr->af == af) session_shutdown(nbr, S_SHUTDOWN, 0, 0); } } diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index 81add63836..7f7ccd1f96 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -192,6 +192,7 @@ int ldpe_imsg_compose_parent(int, pid_t, void *, uint16_t); int ldpe_imsg_compose_lde(int, uint32_t, pid_t, void *, uint16_t); +int ldpe_acl_check(char *, int, union ldpd_addr *, uint8_t); void ldpe_reset_nbrs(int); void ldpe_reset_ds_nbrs(void); void ldpe_remove_dynamic_tnbrs(int); diff --git a/lib/filter.c b/lib/filter.c index cd17a562f0..46e0bbe804 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -1259,6 +1259,14 @@ filter_set_zebra (struct vty *vty, const char *name_str, const char *type_str, struct access_list *access; struct prefix p; + if (strlen(name_str) > ACL_NAMSIZ) + { + vty_out (vty, "%% ACL name %s is invalid: length exceeds " + "%d characters%s", + name_str, ACL_NAMSIZ, VTY_NEWLINE); + return CMD_WARNING; + } + /* Check of filter type. */ if (strncmp (type_str, "p", 1) == 0) type = FILTER_PERMIT; diff --git a/lib/filter.h b/lib/filter.h index e6ccd33b3a..6b5ccb52ec 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -25,6 +25,9 @@ #include "if.h" +/* Maximum ACL name length */ +#define ACL_NAMSIZ 128 + /* Filter direction. */ #define FILTER_IN 0 #define FILTER_OUT 1 diff --git a/tools/xml2cli.pl b/tools/xml2cli.pl index e0980421bd..40f905bcde 100755 --- a/tools/xml2cli.pl +++ b/tools/xml2cli.pl @@ -42,6 +42,8 @@ use XML::LibXML; "ipv6" => "X:X::X:X", "ipv6m" => "X:X::X:X/M", "mtu" => "(1500-9180)", + "acl_range" => "(1-199)", + "acl_expanded_range" => "(1300-2699)", # BGP specific "rd" => "ASN:nn_or_IP-address:nn", "asn" => "(1-4294967295)", @@ -207,7 +209,7 @@ sub generate_code { } # update the command string - if ($node{'function'} ne "inherited") { + if ($node{'function'} ne "inherited" and $node{'function'}) { $function = $node{'function'}; } } |
