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 <renato@opensourcerouting.org>
This commit is contained in:
Renato Westphal 2017-01-27 14:22:47 -02:00
parent 28e8294caa
commit 45a8eba972
14 changed files with 562 additions and 96 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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 *,

View File

@ -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);

View File

@ -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 *[]);

View File

@ -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>

View File

@ -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);

View File

@ -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

View File

@ -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 *);

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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'};
}
}