]> git.puffer.fish Git - matthieu/frr.git/commitdiff
ldpd: introduce advanced filtering capabilities
authorRenato Westphal <renato@opensourcerouting.org>
Fri, 27 Jan 2017 16:22:47 +0000 (14:22 -0200)
committerRenato Westphal <renato@opensourcerouting.org>
Thu, 2 Feb 2017 00:03:36 +0000 (22:03 -0200)
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>
14 files changed:
ldpd/hello.c
ldpd/lde.c
ldpd/lde.h
ldpd/lde_lib.c
ldpd/ldp_vty.h
ldpd/ldp_vty.xml
ldpd/ldp_vty_conf.c
ldpd/ldpd.c
ldpd/ldpd.h
ldpd/ldpe.c
ldpd/ldpe.h
lib/filter.c
lib/filter.h
tools/xml2cli.pl

index 95be1d51113cab047f824d69243d921c3183daac..e7935899b71fe8e96763188f516ff0056ca2ff71 100644 (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);
index a28862881d7c8e177b6bbbb0063fae1697d62948..ff8004720708020232abd3773f0e5ba4d03cf4dd 100644 (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,
index fe90b2c8524bae34cd77d80a2ae73cb593c842bb..7fa5219b121cdf22ec95be741b8df2e378f785bb 100644 (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 *,
index df65edad1a3d5b8d1c84c816363961752e9bdbde..7a4cb760f13f68b8c48c122309099a3f3bc4bb21 100644 (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);
index 735554badfe57ad1d3e88b349e363a756becbfb8..b0dc2914344c8e03b988459a7c34ca1193245c89 100644 (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 *[]);
index 794f063c4d91c39c4be83d544f7a4e732315ddc2..966b634c2724cc5dc3466fe3be440015b174882a 100644 (file)
     <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">
     <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>
index e408abb091a1b3a57ab6ea9a94224458f2dae67b..792f8c8d1bb0b684450efbbe1741c96a764ebaf4 100644 (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);
 
index 6fd4251edcd416474f1d21e882d6260b014e5f96..76eb66d9263808960a7c5adff288e94cbe48433f 100644 (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
index 2c9706cf477f230bb670cfa2412a45ef510b9951..506891ff0733ca7aa23aab7b14e15715a4a0d7f8 100644 (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 *);
index 236e71f3220f857ed79b7d6b9d395cf6de818993..0b441c181344a8da26afa47b579c79047fa8f586 100644 (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);
        }
 }
index 81add63836d629ff8cba67065f8345f1a59230e7..7f7ccd1f96deed202cf81e52a55dfd5dafde4dbb 100644 (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);
index cd17a562f01a3b6124173d7f279ef4df87e04fc4..46e0bbe804f78c1fab36b50d8e849d082d3f47dd 100644 (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;
index e6ccd33b3a33ad0c6251751a8b8a003631e8b685..6b5ccb52ec5291f89dc9d16afa27678676afbe9a 100644 (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
index e0980421bd844be193cc296ea77d02738ad4c91f..40f905bcdecefd56442590ca86d714c868be0484 100755 (executable)
@@ -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'};
                }
        }