]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
L3VPN: Add support for import/export target none and import target all master oz-test
authorOndrej Zajicek <santiago@crfreenet.org>
Fri, 19 Sep 2025 16:46:41 +0000 (18:46 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Fri, 19 Sep 2025 16:46:41 +0000 (18:46 +0200)
The patch adds support for 'import/export target none' (or '[]' to
specify an empty set). It can be used when we do not want to import/export
any route from/to the VRF, or if we prefer to set the RT it in filters
(e.g., adding a different RT for different IP prefixes).

The patch also adds support for 'import target all', i.e. all VPN routes
are imported in the VRF IP table regardless of the RTs. Useful when more
complexx policy implemented in filters.

Based on patches from Sébastien Parisot <sparisot@iliad-free.fr>, thanks!

doc/bird.sgml
proto/l3vpn/config.Y
proto/l3vpn/l3vpn.c
proto/l3vpn/l3vpn.h

index 98a480f79bdec454dd5cc8447263c943032fcaae..a61400ef87f8852811786d09e3bcdc455fa849f6 100644 (file)
@@ -4557,18 +4557,18 @@ could have up to 5 channels: <cf/ipv4/, <cf/ipv6/, <cf/vpn4/, <cf/vpn6/, and
        <tag><label id="l3vpn-rd">rd <m/rd/</tag>
        A shorthand for the option <cf/route distinguisher/.
 
-       <tag><label id="l3vpn-import-target">import target <m/ec/|<m/ec-set/</tag>
+       <tag><label id="l3vpn-import-target">import target <m/ec/|<m/ec-set/|none|all</tag>
        Route target extended communities specifying which routes should be
        imported. Either one community or a set. A route is imported if there is
        non-empty intersection between extended communities of the route and the
        import target of the L3VPN protocol. Mandatory.
 
-       <tag><label id="l3vpn-export-target">export target <m/ec/|<m/ec-set/</tag>
+       <tag><label id="l3vpn-export-target">export target <m/ec/|<m/ec-set/|none</tag>
        Route target extended communities that are attached to the route in the
        export direction. Either one community or a set. Other route target
        extended communities are removed. Mandatory.
 
-       <tag><label id="l3vpn-route-target">route target <m/ec/|<m/ec-set/</tag>
+       <tag><label id="l3vpn-route-target">route target <m/ec/|<m/ec-set/|none</tag>
        A shorthand for both <cf/import target/ and <cf/export target/.
 </descrip>
 
index e16e0c488a5bc8a1b01e73e64847116a0fdbd348..4048b9c9008172523ed71eff4e98211922c9cad5 100644 (file)
@@ -67,6 +67,9 @@ l3vpn_channel: l3vpn_channel_start channel_opt_list channel_end;
 l3vpn_proto_start: proto_start L3VPN
 {
   this_proto = proto_config_new(&proto_l3vpn, $1);
+
+  L3VPN_CFG->import_target = RT_UNDEF;
+  L3VPN_CFG->export_target = RT_UNDEF;
 };
 
 
@@ -76,6 +79,7 @@ l3vpn_proto_item:
  | mpls_channel
  | RD VPN_RD { L3VPN_CFG->rd = $2; }
  | ROUTE DISTINGUISHER VPN_RD { L3VPN_CFG->rd = $3; }
+ | IMPORT TARGET ALL { L3VPN_CFG->import_target = RT_ALL; }
  | IMPORT TARGET l3vpn_targets { L3VPN_CFG->import_target = $3; }
  | EXPORT TARGET l3vpn_targets { L3VPN_CFG->export_target = $3; }
  | ROUTE TARGET l3vpn_targets { L3VPN_CFG->import_target = L3VPN_CFG->export_target = $3; }
@@ -93,6 +97,8 @@ l3vpn_proto:
 l3vpn_targets:
    ec_item { f_tree_only_rt($1); $$ = $1; }
  | '[' ec_items ']' { f_tree_only_rt($2); $$ = build_tree($2); }
+ | '[' ']' { $$ = RT_NONE; }
+ | NONE { $$ = RT_NONE; }
  ;
 
 
index bd5fbdaf00a43cb61cb9c92a62b8e016cc946b82..ece79d597577939f527f4c10ad63f6de2193cfc6 100644 (file)
@@ -53,7 +53,6 @@
  * - check for simple nodes in export route
  * - replace pair of channels with shared channel for one address family
  * - improve route comparisons in VRFs
- * - optional import/export target all
  * - optional support for route origins
  * - optional automatic assignment of RDs
  * - MPLS-in-IP encapsulation
@@ -81,9 +80,20 @@ mpls_valid_nexthop(const rta *a)
   return 1;
 }
 
+const struct f_tree l3vpn_rt_all = {
+  .from = { .type = T_EC, .val.ec = 0 },
+  .to = { .type = T_EC, .val.ec = ~0 },
+};
+
 static int
 l3vpn_import_targets(struct l3vpn_proto *p, const struct adata *list)
 {
+  if (p->import_target == RT_ALL)
+    return 1;
+
+  if (p->import_target == RT_NONE)
+    return 0;
+
   return (p->import_target_one) ?
     ec_set_contains(list, p->import_target->from.val.ec) :
     eclist_match_set(list, p->import_target);
@@ -124,7 +134,7 @@ static inline void
 l3vpn_prepare_import_targets(struct l3vpn_proto *p)
 {
   const struct f_tree *t = p->import_target;
-  p->import_target_one = !t->left && !t->right && (t->from.val.ec == t->to.val.ec);
+  p->import_target_one = t && !t->left && !t->right && (t->from.val.ec == t->to.val.ec);
 }
 
 static void
@@ -334,13 +344,13 @@ l3vpn_postconfig(struct proto_config *CF)
   if (rd_zero(cf->rd))
     cf_error("Route distinguisher not specified");
 
-  if (!cf->import_target && !cf->export_target)
+  if ((cf->import_target == RT_UNDEF) && (cf->export_target == RT_UNDEF))
     cf_error("Route target not specified");
 
-  if (!cf->import_target)
+  if (cf->import_target == RT_UNDEF)
     cf_error("Import target not specified");
 
-  if (!cf->export_target)
+  if (cf->export_target == RT_UNDEF)
     cf_error("Export target not specified");
 }
 
index 1cce28faacd84cd509fc4e36c0ab7747a2dde209..6ef4b22ba985dfce303de0318288ee2bccbccc00 100644 (file)
 #ifndef _BIRD_L3VPN_H_
 #define _BIRD_L3VPN_H_
 
+extern const struct f_tree l3vpn_rt_all;
+
+#define RT_ALL         (&l3vpn_rt_all)
+#define RT_NONE                ((struct f_tree *) NULL)
+#define RT_UNDEF       ((struct f_tree *) 1)
+
 struct l3vpn_config {
   struct proto_config c;
 
   vpn_rd rd;
-  struct f_tree *import_target;
-  struct f_tree *export_target;
+  const struct f_tree *import_target;
+  const struct f_tree *export_target;
 };
 
 struct l3vpn_proto {
@@ -26,8 +32,8 @@ struct l3vpn_proto {
   struct channel *vpn6_channel;
 
   vpn_rd rd;
-  struct f_tree *import_target;
-  struct f_tree *export_target;
+  const struct f_tree *import_target;
+  const struct f_tree *export_target;
   u32 *export_target_data;
   uint export_target_length;
   uint import_target_one;