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 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -70,13 +111,33 @@
-
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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'};
}
}