]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Nest: Allow modification of channels inherited from templates
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 9 Jan 2018 17:42:22 +0000 (18:42 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Tue, 9 Jan 2018 17:42:22 +0000 (18:42 +0100)
Multiple definitions of same channels are forbidden, but inherited
channel can be redefined. In such case channel options are merged.

doc/bird.sgml
nest/config.Y
nest/proto.c
nest/protocol.h
proto/bgp/config.Y
proto/ospf/config.Y
proto/pipe/config.Y
proto/radv/radv.c
proto/rip/rip.c
proto/rpki/rpki.c

index 3a2607b42a5c7277717ca1c095ea2014d402af08..bde825c3f1439d10cc766e4ab09a63778096cf58 100644 (file)
@@ -407,31 +407,33 @@ extensive way.
 a comment, whitespace characters are treated as a single space. If there's a
 variable number of options, they are grouped using the <cf/{ }/ brackets. Each
 option is terminated by a <cf/;/. Configuration is case sensitive. There are two
-ways how to name symbols (like protocol names, filter names, constants etc.). You
-can either use a simple string starting with a letter followed by any
-combination of letters and numbers (e.g. <cf/R123/, <cf/myfilter/, <cf/bgp5/) or you can
-enclose the name into apostrophes (<cf/'/) and than you can use any combination
-of numbers, letters. hyphens, dots and colons (e.g. <cf/'1:strange-name'/,
-<cf/'-NAME-'/, <cf/'cool::name'/).
+ways how to name symbols (like protocol names, filter names, constants etc.).
+You can either use a simple string starting with a letter followed by any
+combination of letters and numbers (e.g. <cf/R123/, <cf/myfilter/, <cf/bgp5/) or
+you can enclose the name into apostrophes (<cf/'/) and than you can use any
+combination of numbers, letters. hyphens, dots and colons (e.g.
+<cf/'1:strange-name'/, <cf/'-NAME-'/, <cf/'cool::name'/).
 
 <p>Here is an example of a simple config file. It enables synchronization of
-routing tables with OS kernel, scans for new network interfaces every 10 seconds
-and runs RIP on all network interfaces found.
+routing tables with OS kernel, learns network interfaces and runs RIP on all
+network interfaces found.
 
 <code>
 protocol kernel {
+       ipv4 {
+               export all;     # Default is export none
+       };
        persist;                # Don't remove routes on BIRD shutdown
-       scan time 20;           # Scan kernel routing table every 20 seconds
-       export all;             # Default is export none
 }
 
 protocol device {
-       scan time 10;           # Scan interfaces every 10 seconds
 }
 
 protocol rip {
-       export all;
-       import all;
+       ipv4 {
+               import all;
+               export all;
+       };
        interface "*";
 }
 </code>
@@ -775,8 +777,10 @@ agreement").
 <label id="channel-opts">
 
 <p>Every channel belongs to a protocol and is configured inside its block. The
-minimal channel config is empty, then it uses the default values. The name of
-the channel implies its nettype.
+minimal channel config is empty, then it uses default values. The name of the
+channel implies its nettype. Channel definitions can be inherited from protocol
+templates. Multiple definitions of the same channel are forbidden, but channels
+inherited from templates can be updated by new definitions.
 
 <descrip>
        <tag><label id="proto-table">table <m/name/</tag>
@@ -841,7 +845,7 @@ protocol rip ng {
 }
 </code>
 
-<p>And this is a non-trivial example.
+<p>This is a non-trivial example.
 <code>
 protocol rip ng {
        ipv6 {
@@ -854,6 +858,33 @@ protocol rip ng {
 }
 </code>
 
+<p>And this is even more complicated example using templates.
+<code>
+template bgp {
+       local 198.51.100.14 as 65000;
+
+       ipv4 {
+               table mytable4;
+               import filter { ... };
+       };
+       ipv6 {
+               table mytable6;
+               import filter { ... };
+       };
+}
+
+protocol bgp from  {
+       neighbor 198.51.100.130 as 64496;
+
+       # IPv4 channel is inherited as-is, while IPv6
+       # channel is adjusted by export filter option
+       ipv6 {
+               export filter { ... };
+       };
+}
+</code>
+
+
 <chapt>Remote control
 <label id="remote-control">
 
@@ -1051,6 +1082,7 @@ This argument can be omitted if there exists only a single instance.
        Evaluate given expression.
 </descrip>
 
+
 <chapt>Filters
 <label id="filters">
 
@@ -2427,7 +2459,7 @@ together with their appropriate channels follows.
 </tabular>
 </table>
 
-<p>BGP's channels have additional config options (together with the common ones):
+<p>BGP channels have additional config options (together with the common ones):
 
 <descrip>
        <tag><label id="bgp-next-hop-keep">next hop keep</tag>
index 5c4f239384af3f9b3cf984f3816b27a0b9cf9842..044aba2b3095bef90832d6094fa71185b68d6385 100644 (file)
@@ -214,7 +214,7 @@ proto_item:
 
 channel_start: net_type
 {
-  $$ = this_channel = channel_config_new(NULL, $1, this_proto);
+  $$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
 };
 
 channel_item:
index e103fec60437fb5544ab87cf849a7d52280ce191..d584cb9302731f2b8bcac5a3c26b477f43e4efec 100644 (file)
@@ -455,11 +455,10 @@ const struct channel_class channel_basic = {
 };
 
 void *
-channel_config_new(const struct channel_class *cc, uint net_type, struct proto_config *proto)
+channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto)
 {
   struct channel_config *cf = NULL;
   struct rtable_config *tab = NULL;
-  const char *name = NULL;
 
   if (net_type)
   {
@@ -470,7 +469,6 @@ channel_config_new(const struct channel_class *cc, uint net_type, struct proto_c
       cf_error("Different channel type");
 
     tab = new_config->def_tables[net_type];
-    name = net_label[net_type];
   }
 
   if (!cc)
@@ -479,6 +477,7 @@ channel_config_new(const struct channel_class *cc, uint net_type, struct proto_c
   cf = cfg_allocz(cc->config_size);
   cf->name = name;
   cf->channel = cc;
+  cf->parent = proto;
   cf->table = tab;
   cf->out_filter = FILTER_REJECT;
 
@@ -491,6 +490,26 @@ channel_config_new(const struct channel_class *cc, uint net_type, struct proto_c
   return cf;
 }
 
+void *
+channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto)
+{
+  struct channel_config *cf;
+
+  /* We are using name as token, so no strcmp() */
+  WALK_LIST(cf, proto->channels)
+    if (cf->name == name)
+    {
+      /* Allow to redefine channel only if inherited from template */
+      if (cf->parent == proto)
+       cf_error("Multiple %s channels", name);
+
+      cf->parent = proto;
+      return cf;
+    }
+
+  return channel_config_new(cc, name, net_type, proto);
+}
+
 struct channel_config *
 channel_copy_config(struct channel_config *src, struct proto_config *proto)
 {
index c8f3736782a055baf57d489476c940d551f6c411..9afd3a0a2f6fc7a63cc6bddfe1258975f5491aa0 100644 (file)
@@ -461,6 +461,7 @@ struct channel_config {
   const char *name;
   const struct channel_class *channel;
 
+  struct proto_config *parent;         /* Where channel is defined (proto or template) */
   struct rtable_config *table;         /* Table we're attached to */
   struct filter *in_filter, *out_filter; /* Attached filters */
   struct channel_limit rx_limit;       /* Limit for receiving routes from protocol
@@ -585,7 +586,8 @@ static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP)
 static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); }
 
 void channel_request_feeding(struct channel *c);
-void *channel_config_new(const struct channel_class *cc, uint net_type, struct proto_config *proto);
+void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
+void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
 int channel_reconfigure(struct channel *c, struct channel_config *cf);
 
 
index 6ce0f1aacbca766a819b7b95608741e69cd686a2..4e819eb7a3b4c846a1f6aa3d31d5385fda534ad0 100644 (file)
@@ -158,12 +158,16 @@ bgp_channel_start: bgp_afi
   if (!desc)
     cf_error("Unknown AFI/SAFI");
 
-  this_channel = channel_config_new(&channel_bgp, desc->net, this_proto);
-  BGP_CC->c.name = desc->name;
-  BGP_CC->c.ra_mode = RA_UNDEF;
-  BGP_CC->afi = $1;
-  BGP_CC->desc = desc;
-  BGP_CC->gr_able = 0xff;      /* undefined */
+  this_channel = channel_config_get(&channel_bgp, desc->name, desc->net, this_proto);
+
+  /* New channel */
+  if (!BGP_CC->desc)
+  {
+    BGP_CC->c.ra_mode = RA_UNDEF;
+    BGP_CC->afi = $1;
+    BGP_CC->desc = desc;
+    BGP_CC->gr_able = 0xff;    /* undefined */
+  }
 };
 
 bgp_channel_item:
index ce409a3a4b43b57b0ed148a92892389c27dde345..005f43817ed0e7cf3aeaffb1a0e292b3d0ebf6b7 100644 (file)
@@ -84,8 +84,8 @@ ospf_proto_finish(void)
   /* Define default channel */
   if (EMPTY_LIST(this_proto->channels))
   {
-    this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
-    channel_config_new(NULL, this_proto->net_type, this_proto);
+    uint net_type = this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
+    channel_config_new(NULL, net_label[net_type], net_type, this_proto);
   }
 
   /* Propagate global instance ID to interfaces */
@@ -238,7 +238,8 @@ ospf_af_mc:
 /* We redefine proto_channel to add multicast flag */
 ospf_channel_start: net_type ospf_af_mc
 {
-  $$ = this_channel = channel_config_new(NULL, $1, this_proto);
+  /* TODO: change name for multicast channels */
+  $$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
 
   /* Save the multicast flag */
   if (this_channel == proto_cf_main_channel(this_proto))
index f51ee5751b552a858c51a7bb15930feaf034f6e8..4f96fdcbcba65e421186327a0c883988a8a536cc 100644 (file)
@@ -25,7 +25,7 @@ CF_ADDTO(proto, pipe_proto '}' { this_channel = NULL; } )
 pipe_proto_start: proto_start PIPE
 {
   this_proto = proto_config_new(&proto_pipe, $1);
-  this_channel = channel_config_new(NULL, 0, this_proto);
+  this_channel = channel_config_new(NULL, NULL, 0, this_proto);
   this_channel->in_filter = FILTER_ACCEPT;
   this_channel->out_filter = FILTER_ACCEPT;
 };
index 0a2a3e78a4b5e839f126f729e74c82e481c3e452..8a79dfaf245851f57768dafc14a5c40590dbce18 100644 (file)
@@ -569,7 +569,7 @@ radv_postconfig(struct proto_config *CF)
 
   /* Define default channel */
   if (EMPTY_LIST(CF->channels))
-    channel_config_new(NULL, NET_IP6, CF);
+    channel_config_new(NULL, net_label[NET_IP6], NET_IP6, CF);
 }
 
 static struct proto *
index a3eeaf177b66a909b2127126018da6ac3e20361f..85e37cea2ea08b8cc5257a01d8625e7f9c70a592 100644 (file)
@@ -1078,7 +1078,7 @@ rip_postconfig(struct proto_config *CF)
 
   /* Define default channel */
   if (EMPTY_LIST(CF->channels))
-    channel_config_new(NULL, CF->net_type, CF);
+    channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF);
 }
 
 static struct proto *
index 3145399b2734e3a7734171065fa315d73a597e43..74860071aaa43d49414116930cad25265d33c10a 100644 (file)
@@ -901,7 +901,7 @@ rpki_postconfig(struct proto_config *CF)
 {
   /* Define default channel */
   if (EMPTY_LIST(CF->channels))
-    channel_config_new(NULL, CF->net_type, CF);
+    channel_config_new(NULL, net_label[CF->net_type], CF->net_type, CF);
 }
 
 static void