]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Implements protocol templates.
authorOndrej Zajicek <santiago@crfreenet.org>
Sun, 6 Nov 2011 23:31:23 +0000 (00:31 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Sun, 6 Nov 2011 23:31:23 +0000 (00:31 +0100)
Based on the patch from Alexander V. Chernikov.
Extended to support almost all protocols.
Uses 'protocol bgp NAME from TEMPLATE { ... }' syntax.

34 files changed:
conf/cf-lex.l
conf/conf.c
conf/conf.h
doc/bird.conf.example
doc/bird.sgml
nest/config.Y
nest/proto.c
nest/protocol.h
nest/rt-dev.c
nest/rt-dev.h
proto/bgp/bgp.c
proto/bgp/bgp.h
proto/bgp/config.Y
proto/ospf/config.Y
proto/ospf/ospf.h
proto/pipe/config.Y
proto/pipe/pipe.c
proto/radv/radv.c
proto/radv/radv.h
proto/rip/config.Y
proto/rip/rip.c
proto/static/config.Y
proto/static/static.c
sysdep/bsd/krt-iface.h
sysdep/bsd/krt-scan.h
sysdep/bsd/krt-sock.h
sysdep/linux/netlink/krt-iface.h
sysdep/linux/netlink/krt-scan.h
sysdep/linux/netlink/krt-set.h
sysdep/unix/krt-iface.h
sysdep/unix/krt-set.h
sysdep/unix/krt.Y
sysdep/unix/krt.c
sysdep/unix/krt.h

index 02ba4b3945cb3ab92217d7f218764cb0d090b42f..ddfe8c77939adc3530ee84af2231050a6a1581ac 100644 (file)
@@ -533,6 +533,8 @@ cf_symbol_class_name(struct symbol *sym)
       return "routing table";
     case SYM_IPA:
       return "network address";
+    case SYM_TEMPLATE:
+      return "protocol template";
     default:
       return "unknown type";
     }
index 5bdeece27779cd2403a47fbab0e15b96f17350c6..4b605b36255c90df1ecb03e9a8864335a3bdd764 100644 (file)
@@ -377,3 +377,18 @@ cfg_strdup(char *c)
   memcpy(z, c, l);
   return z;
 }
+
+
+void
+cfg_copy_list(list *dest, list *src, unsigned node_size)
+{
+  node *dn, *sn;
+
+  init_list(dest);
+  WALK_LIST(sn, *src)
+  {
+    dn = cfg_alloc(node_size);
+    memcpy(dn, sn, node_size);
+    add_tail(dest, dn);
+  }
+}
index 142c6adeabc221f0295592bc0ab38b6c71709c01..8753bafe420a6ef4942bb07ed16854f4f7886caa 100644 (file)
@@ -84,6 +84,7 @@ extern linpool *cfg_mem;
 #define cfg_allocu(size) lp_allocu(cfg_mem, size)
 #define cfg_allocz(size) lp_allocz(cfg_mem, size)
 char *cfg_strdup(char *c);
+void cfg_copy_list(list *dest, list *src, unsigned node_size);
 
 /* Lexer */
 
@@ -108,6 +109,7 @@ struct symbol {
 #define SYM_FILTER 4
 #define SYM_TABLE 5
 #define SYM_IPA 6
+#define SYM_TEMPLATE 7
 
 #define SYM_VARIABLE 0x100     /* 0x100-0x1ff are variable types */
 
index 339898f29c2b70b3cf4c8e6898c204d9f519a628..5e07ab5a51092a5413c06eca5c178db00c722b7e 100644 (file)
@@ -202,3 +202,16 @@ protocol static {
 #              reject;
 #      };
 #}
+# 
+# Template usage example
+#template bgp rr_client {
+#      disabled;
+#      local as 65000;
+#      multihop;
+#      rr client;
+#      rr cluster id 1.0.0.1;
+#}
+#
+#protocol bgp rr_abcd from rr_client {
+#      neighbor 10.1.4.7 as 65000;
+#}
index d454629362dc810a346829a2b2c05ba3180cbbdc..7f53f028c37966d91396a6bdf9c2432acf04dfbb 100644 (file)
@@ -296,10 +296,21 @@ protocol rip {
        <tag>function <m/name/ (<m/parameters/) <m/local variables/ { <m/commands/ }</tag> Define a function. You can learn more
        about functions in the following chapter.
  
-       <tag>protocol rip|ospf|bgp|... <m/[name]/ { <m>protocol options</m> }</tag> Define a protocol
-       instance called <cf><m/name/</cf> (or with a name like "rip5" generated automatically if you don't specify any <cf><m/name/</cf>). You can learn more
-       about configuring protocols in their own chapters. You can run more than one instance of
-       most protocols (like RIP or BGP). By default, no instances are configured.
+       <tag>protocol rip|ospf|bgp|... [<m/name/ [from <m/name2/]] { <m>protocol options</m> }</tag>
+       Define a protocol instance called <cf><m/name/</cf> (or with a name like "rip5" generated
+       automatically if you don't specify any <cf><m/name/</cf>). You can learn more about
+       configuring protocols in their own chapters. When <cf>from <m/name2/</cf> expression is
+       used, initial protocol options are taken from protocol or template <cf><m/name2/</cf>
+       You can run more than one instance of most protocols (like RIP or BGP). By default, no
+       instances are configured.
+
+       <tag>template rip|bgp|... [<m/name/ [from <m/name2/]] { <m>protocol options</m> }</tag>
+       Define a protocol template instance called <cf><m/name/</cf> (or with a name like "bgp1"
+       generated automatically if you don't specify any <cf><m/name/</cf>). Protocol templates can
+       be used to group common options when many similarly configured protocol instances are to be
+       defined. Protocol instances (and other templates) can use templates by using <cf/from/
+       expression and the name of the template. At the moment templates (and <cf/from/ expression)
+       are not implemented for OSPF protocol.
 
        <tag>define <m/constant/ = (<m/expression/)|<m/number/|<m/IP address/</tag>
        Define a constant. You can use it later in every place you could use a simple integer or an IP address.
index dd4a9e00b9e638d0e461c88a6ce60d2785850e71..a6baf4ead8dde6f1c9671a71870fd9fd6ede8fe3 100644 (file)
@@ -26,7 +26,7 @@ static int password_id;
 static inline void
 reset_passwords(void)
 {
- this_p_list = NULL;
 this_p_list = NULL;
 }
 
 static inline list *
@@ -37,10 +37,11 @@ get_passwords(void)
   return rv;
 }
 
+#define DIRECT_CFG ((struct rt_dev_config *) this_proto)
 
 CF_DECLS
 
-CF_KEYWORDS(ROUTER, ID, PROTOCOL, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
+CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
 CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
 CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
 CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE)
@@ -58,7 +59,7 @@ CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT, MULT
 %type <r> rtable
 %type <s> optsym
 %type <ra> r_args
-%type <i> echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport
+%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport
 %type <ps> proto_patt proto_patt2
 
 CF_GRAMMAR
@@ -115,20 +116,30 @@ newtab: TABLE SYM {
 
 CF_ADDTO(conf, proto)
 
-proto_start: PROTOCOL
+proto_start:
+   PROTOCOL { $$ = SYM_PROTO; }
+ | TEMPLATE { $$ = SYM_TEMPLATE; }
  ;
 
 proto_name:
    /* EMPTY */ {
      struct symbol *s = cf_default_name(this_proto->protocol->template, &this_proto->protocol->name_counter);
-     s->class = SYM_PROTO;
+     s->class = this_proto->class;
      s->def = this_proto;
      this_proto->name = s->name;
      }
  | SYM {
-     cf_define_symbol($1, SYM_PROTO, this_proto);
+     cf_define_symbol($1, this_proto->class, this_proto);
      this_proto->name = $1->name;
    }
+ | SYM FROM SYM {
+     if (($3->class != SYM_TEMPLATE) && ($3->class != SYM_PROTO)) cf_error("Template or protocol name expected");
+
+     cf_define_symbol($1, this_proto->class, this_proto);
+     this_proto->name = $1->name;
+
+     proto_copy_config(this_proto, $3->def);
+   }
  ;
 
 proto_item:
@@ -207,10 +218,9 @@ iface_patt_list:
 CF_ADDTO(proto, dev_proto '}')
 
 dev_proto_start: proto_start DIRECT {
-     struct rt_dev_config *p = proto_config_new(&proto_device, sizeof(struct rt_dev_config));
-     this_proto = &p->c;
-     p->c.preference = DEF_PREF_DIRECT;
-     init_list(&p->iface_list);
+     this_proto = proto_config_new(&proto_device, sizeof(struct rt_dev_config), $1);
+     this_proto->preference = DEF_PREF_DIRECT;
+     init_list(&DIRECT_CFG->iface_list);
    }
  ;
 
@@ -222,9 +232,8 @@ dev_proto:
 
 dev_iface_init:
    /* EMPTY */ {
-     struct rt_dev_config *p = (void *) this_proto;
      this_ipatt = cfg_allocz(sizeof(struct iface_patt));
-     add_tail(&p->iface_list, NODE this_ipatt);
+     add_tail(&DIRECT_CFG->iface_list, NODE this_ipatt);
      init_list(&this_ipatt->ipn_list);
    }
  ;
index 4a154d5902523eeda764f5eb15b689ffcbc30e73..d55c348d25bea5a2bd27ffd0367baee7267c8d26 100644 (file)
@@ -175,6 +175,7 @@ proto_flush_hooks(struct proto *p)
  * proto_config_new - create a new protocol configuration
  * @pr: protocol the configuration will belong to
  * @size: size of the structure including generic data
+ * @class: SYM_PROTO or SYM_TEMPLATE
  *
  * Whenever the configuration file says that a new instance
  * of a routing protocol should be created, the parser calls
@@ -183,16 +184,23 @@ proto_flush_hooks(struct proto *p)
  * containing all the generic items followed by protocol-specific
  * ones). Also, the configuration entry gets added to the list
  * of protocol instances kept in the configuration.
+ *
+ * The function is also used to create protocol templates (when class
+ * SYM_TEMPLATE is specified), the only difference is that templates
+ * are not added to the list of protocol instances and therefore not
+ * initialized during protos_commit()).
  */
 void *
-proto_config_new(struct protocol *pr, unsigned size)
+proto_config_new(struct protocol *pr, unsigned size, int class)
 {
   struct proto_config *c = cfg_allocz(size);
 
-  add_tail(&new_config->protos, &c->n);
+  if (class == SYM_PROTO)
+    add_tail(&new_config->protos, &c->n);
   c->global = new_config;
   c->protocol = pr;
   c->name = pr->name;
+  c->class = class;
   c->out_filter = FILTER_REJECT;
   c->table = c->global->master_rtc;
   c->debug = new_config->proto_default_debug;
@@ -200,6 +208,50 @@ proto_config_new(struct protocol *pr, unsigned size)
   return c;
 }
 
+/**
+ * proto_copy_config - copy a protocol configuration
+ * @dest: destination protocol configuration
+ * @src: source protocol configuration
+ *
+ * Whenever a new instance of a routing protocol is created from the
+ * template, proto_copy_config() is called to copy a content of
+ * the source protocol configuration to the new protocol configuration.
+ * Name, class and a node in protos list of @dest are kept intact.
+ * copy_config() protocol hook is used to copy protocol-specific data.
+ */
+void
+proto_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+  node old_node;
+  int old_class;
+  char *old_name;
+
+  if (dest->protocol != src->protocol)
+    cf_error("Can't copy configuration from a different protocol type");
+
+  if (dest->protocol->copy_config == NULL)
+    cf_error("Inheriting configuration for %s is not supported", src->protocol->name);
+
+  DBG("Copying configuration from %s to %s\n", src->name, dest->name);
+
+  /* 
+   * Copy struct proto_config here. Keep original node, class and name.
+   * protocol-specific config copy is handled by protocol copy_config() hook
+   */
+
+  old_node = dest->n;
+  old_class = dest->class;
+  old_name = dest->name;
+
+  memcpy(dest, src, sizeof(struct proto_config));
+
+  dest->n = old_node;
+  dest->class = old_class;
+  dest->name = old_name;
+
+  dest->protocol->copy_config(dest, src);
+}
+
 /**
  * protos_preconfig - pre-configuration processing
  * @c: new configuration
@@ -230,7 +282,8 @@ protos_preconfig(struct config *c)
  * @c: new configuration
  *
  * This function calls the postconfig() hooks of all protocol
- * instances specified in configuration @c.
+ * instances specified in configuration @c. The hooks are not
+ * called for protocol templates.
  */
 void
 protos_postconfig(struct config *c)
@@ -366,14 +419,15 @@ protos_commit(struct config *new, struct config *old, int force_reconfig, int ty
 {
   struct proto_config *oc, *nc;
   struct proto *p, *n;
+  struct symbol *sym;
 
   DBG("protos_commit:\n");
   if (old)
     {
       WALK_LIST(oc, old->protos)
        {
-         struct proto *p = oc->proto;
-         struct symbol *sym = cf_find_symbol(oc->name);
+         p = oc->proto;
+         sym = cf_find_symbol(oc->name);
          if (sym && sym->class == SYM_PROTO && !new->shutdown)
            {
              /* Found match, let's check if we can smoothly switch to new configuration */
index f95905aefcb98d8bce175fe4931ea5ad91e54403..a7518c2aa67ccd3832fc84d5de14875472ce27fe 100644 (file)
@@ -53,6 +53,7 @@ struct protocol {
   void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); /* Get route information (for `show route' command) */
   int (*get_attr)(struct eattr *, byte *buf, int buflen);      /* ASCIIfy dynamic attribute (returns GA_*) */
   void (*show_proto_info)(struct proto *);     /* Show protocol info (for `show protocols all' command) */
+  void (*copy_config)(struct proto_config *, struct proto_config *);   /* Copy config from given protocol instance */
 };
 
 void protos_build(void);
@@ -85,12 +86,15 @@ struct proto_config {
   struct proto *proto;                 /* Instance we've created */
   char *name;
   char *dsc;
+  int class;                           /* SYM_PROTO or SYM_TEMPLATE */
   u32 debug, mrtdump;                  /* Debugging bitfields, both use D_* constants */
   unsigned preference, disabled;       /* Generic parameters */
   u32 router_id;                       /* Protocol specific router ID */
   struct rtable_config *table;         /* Table we're attached to */
   struct filter *in_filter, *out_filter; /* Attached filters */
 
+  /* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
+
   /* Protocol-specific data follow... */
 };
 
@@ -203,9 +207,14 @@ struct proto_spec {
 
 
 void *proto_new(struct proto_config *, unsigned size);
-void *proto_config_new(struct protocol *, unsigned size);
+void *proto_config_new(struct protocol *, unsigned size, int class);
+void proto_copy_config(struct proto_config *dest, struct proto_config *src);
 void proto_request_feeding(struct proto *p);
 
+static inline void
+proto_copy_rest(struct proto_config *dest, struct proto_config *src, unsigned size)
+{ memcpy(dest + 1, src + 1, size - sizeof(struct proto_config)); }
+
 void proto_cmd_show(struct proto *, unsigned int, int);
 void proto_cmd_disable(struct proto *, unsigned int, int);
 void proto_cmd_enable(struct proto *, unsigned int, int);
index 239bd268aa0dd0a0bbb9d5c199c892f1701ffe13..497ee8080e4ab76bda660a8e173e4cd80eff2fe7 100644 (file)
@@ -92,9 +92,24 @@ dev_reconfigure(struct proto *p, struct proto_config *new)
   return iface_patts_equal(&o->iface_list, &n->iface_list, NULL);
 }
 
+static void
+dev_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+  struct rt_dev_config *d = (struct rt_dev_config *) dest;
+  struct rt_dev_config *s = (struct rt_dev_config *) src;
+
+  /*
+   * We copy iface_list as ifaces can be shared by more direct protocols.
+   * Copy suffices to be is shallow, because new nodes can be added, but
+   * old nodes cannot be modified (although they contain internal lists).
+   */
+  cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct iface_patt));
+}
+
 struct protocol proto_device = {
   name:                "Direct",
   template:    "direct%d",
   init:                dev_init,
-  reconfigure: dev_reconfigure
+  reconfigure: dev_reconfigure,
+  copy_config: dev_copy_config
 };
index 64f2cd95e010d2b10338a36f74a0eec0d1e3dac5..c36d074238c99f0cf48fa55f4e2078923100ef3f 100644 (file)
@@ -11,7 +11,7 @@
 
 struct rt_dev_config {
   struct proto_config c;
-  list iface_list;
+  list iface_list;             /* list of struct iface_patt */
 };
 
 #endif
index 4e4ca9f395aed4a671a83b0b9c807e726d4da5ff..675342de8fddb9cb76ee696b64603c08207d5471 100644 (file)
@@ -919,6 +919,73 @@ bgp_init(struct proto_config *C)
   return P;
 }
 
+
+void
+bgp_check_config(struct bgp_config *c)
+{
+  int internal = (c->local_as == c->remote_as);
+
+  /* Do not check templates at all */
+  if (c->c.class == SYM_TEMPLATE)
+    return;
+
+  if (!c->local_as)
+    cf_error("Local AS number must be set");
+
+  if (!c->remote_as)
+    cf_error("Neighbor must be configured");
+
+  if (!(c->capabilities && c->enable_as4) && (c->remote_as > 0xFFFF))
+    cf_error("Neighbor AS number out of range (AS4 not available)");
+
+  if (!internal && c->rr_client)
+    cf_error("Only internal neighbor can be RR client");
+
+  if (internal && c->rs_client)
+    cf_error("Only external neighbor can be RS client");
+
+  if (c->multihop && (c->gw_mode == GW_DIRECT))
+    cf_error("Multihop BGP cannot use direct gateway mode");
+
+  /* Different default based on rs_client */
+  if (!c->missing_lladdr)
+    c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF;
+
+  /* Different default for gw_mode */
+  if (!c->gw_mode)
+    c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT;
+}
+
+static int
+bgp_reconfigure(struct proto *P, struct proto_config *C)
+{
+  struct bgp_config *new = (struct bgp_config *) C;
+  struct bgp_proto *p = (struct bgp_proto *) P;
+  struct bgp_config *old = p->cf;
+
+  int same = !memcmp(((byte *) old) + sizeof(struct proto_config),
+                    ((byte *) new) + sizeof(struct proto_config),
+                    // password item is last and must be checked separately
+                    OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config))
+    && ((!old->password && !new->password)
+       || (old->password && new->password && !strcmp(old->password, new->password)))
+    && (get_igp_table(old) == get_igp_table(new));
+
+  /* We should update our copy of configuration ptr as old configuration will be freed */
+  if (same)
+    p->cf = new;
+
+  return same;
+}
+
+static void
+bgp_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+  /* Just a shallow copy */
+  proto_copy_rest(dest, src, sizeof(struct bgp_config));
+}
+
+
 /**
  * bgp_error - report a protocol error
  * @c: connection
@@ -983,38 +1050,6 @@ bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code)
   p->last_error_code = code;
 }
 
-void
-bgp_check(struct bgp_config *c)
-{
-  int internal = (c->local_as == c->remote_as);
-
-  if (!c->local_as)
-    cf_error("Local AS number must be set");
-
-  if (!c->remote_as)
-    cf_error("Neighbor must be configured");
-
-  if (!(c->capabilities && c->enable_as4) && (c->remote_as > 0xFFFF))
-    cf_error("Neighbor AS number out of range (AS4 not available)");
-
-  if (!internal && c->rr_client)
-    cf_error("Only internal neighbor can be RR client");
-
-  if (internal && c->rs_client)
-    cf_error("Only external neighbor can be RS client");
-
-  if (c->multihop && (c->gw_mode == GW_DIRECT))
-    cf_error("Multihop BGP cannot use direct gateway mode");
-
-  /* Different default based on rs_client */
-  if (!c->missing_lladdr)
-    c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF;
-
-  /* Different default for gw_mode */
-  if (!c->gw_mode)
-    c->gw_mode = (c->multihop || internal) ? GW_RECURSIVE : GW_DIRECT;
-}
-
 static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established", "Close" };
 static char *bgp_err_classes[] = { "", "Error: ", "Socket: ", "Received: ", "BGP Error: ", "Automatic shutdown: ", ""};
 static char *bgp_misc_errors[] = { "", "Neighbor lost", "Invalid next hop", "Kernel MD5 auth failed", "No listening socket" };
@@ -1124,28 +1159,6 @@ bgp_show_proto_info(struct proto *P)
     }
 }
 
-static int
-bgp_reconfigure(struct proto *P, struct proto_config *C)
-{
-  struct bgp_config *new = (struct bgp_config *) C;
-  struct bgp_proto *p = (struct bgp_proto *) P;
-  struct bgp_config *old = p->cf;
-
-  int same = !memcmp(((byte *) old) + sizeof(struct proto_config),
-                    ((byte *) new) + sizeof(struct proto_config),
-                    // password item is last and must be checked separately
-                    OFFSETOF(struct bgp_config, password) - sizeof(struct proto_config))
-    && ((!old->password && !new->password)
-       || (old->password && new->password && !strcmp(old->password, new->password)))
-    && (get_igp_table(old) == get_igp_table(new));
-
-  /* We should update our copy of configuration ptr as old configuration will be freed */
-  if (same)
-    p->cf = new;
-
-  return same;
-}
-
 struct protocol proto_bgp = {
   name:                        "BGP",
   template:            "bgp%d",
@@ -1155,6 +1168,7 @@ struct protocol proto_bgp = {
   shutdown:            bgp_shutdown,
   cleanup:             bgp_cleanup,
   reconfigure:         bgp_reconfigure,
+  copy_config:         bgp_copy_config,
   get_status:          bgp_get_status,
   get_attr:            bgp_get_attr,
   get_route_info:      bgp_get_route_info,
index 16e8ea89d31cc91f903ef4d8acd2f94a2ea72e5b..437ba3356468011f5207e66d62c877c8536e6c71 100644 (file)
@@ -141,7 +141,7 @@ extern struct linpool *bgp_linpool;
 
 
 void bgp_start_timer(struct timer *t, int value);
-void bgp_check(struct bgp_config *c);
+void bgp_check_config(struct bgp_config *c);
 void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len);
 void bgp_close_conn(struct bgp_conn *c);
 void bgp_update_startup_delay(struct bgp_proto *p);
index 19d757a526956d49417216dad5efada7f29e3ed7..03c233d6b6383d46aff5a88daa4a338ee428e1ee 100644 (file)
@@ -29,10 +29,10 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
 
 CF_GRAMMAR
 
-CF_ADDTO(proto, bgp_proto '}' { bgp_check(BGP_CFG); } )
+CF_ADDTO(proto, bgp_proto '}' { bgp_check_config(BGP_CFG); } )
 
 bgp_proto_start: proto_start BGP {
-     this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config));
+     this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config), $1);
      this_proto->preference = DEF_PREF_BGP;
      BGP_CFG->hold_time = 240;
      BGP_CFG->connect_retry_time = 120;
index ec7da8e23e4e28b54cec2945baffbd1a58b63481..4ada41e842287bc61de9a9dfe7a155257daba974 100644 (file)
@@ -128,7 +128,7 @@ CF_GRAMMAR
 CF_ADDTO(proto, ospf_proto '}' { ospf_proto_finish(); } )
 
 ospf_proto_start: proto_start OSPF {
-     this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config));
+     this_proto = proto_config_new(&proto_ospf, sizeof(struct ospf_config), $1);
      this_proto->preference = DEF_PREF_OSPF;
      init_list(&OSPF_CFG->area_list);
      init_list(&OSPF_CFG->vlink_list);
index 2e99b0ff93f8e080ef014cae5f54ef8116ab73b4..60a34fba505441f03e7144110a6820dcc40fc65b 100644 (file)
@@ -85,8 +85,8 @@ struct ospf_config
   byte rfc1583;
   byte abr;
   int ecmp;
-  list area_list;
-  list vlink_list;
+  list area_list;              /* list of struct ospf_area_config */
+  list vlink_list;             /* list of struct ospf_iface_patt */
 };
 
 struct nbma_node
index e1c981bbf367a975ee9d14a15d1e64bb465823a0..4478afe7ebe6076d3ceb3fcbd719c643d49905e8 100644 (file)
@@ -23,7 +23,7 @@ CF_GRAMMAR
 CF_ADDTO(proto, pipe_proto '}')
 
 pipe_proto_start: proto_start PIPE {
-     this_proto = proto_config_new(&proto_pipe, sizeof(struct pipe_config));
+     this_proto = proto_config_new(&proto_pipe, sizeof(struct pipe_config), $1);
      this_proto->preference = DEF_PREF_PIPE;
      PIPE_CFG->mode = PIPE_TRANSPARENT;
   }
index e557097d776c969dc945426f4ca88a599bd60e29..420c5a9d3705063438b80a6d04bf38d1c3609a4a 100644 (file)
@@ -165,14 +165,6 @@ pipe_postconfig(struct proto_config *C)
     cf_error("Primary table and peer table must be different");
 }
 
-static void
-pipe_get_status(struct proto *P, byte *buf)
-{
-  struct pipe_proto *p = (struct pipe_proto *) P;
-
-  bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer->name);
-}
-
 static int
 pipe_reconfigure(struct proto *P, struct proto_config *new)
 {
@@ -186,6 +178,21 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
   return 1;
 }
 
+static void
+pipe_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+  /* Just a shallow copy, not many items here */
+  proto_copy_rest(dest, src, sizeof(struct pipe_config));
+}
+
+static void
+pipe_get_status(struct proto *P, byte *buf)
+{
+  struct pipe_proto *p = (struct pipe_proto *) P;
+
+  bsprintf(buf, "%c> %s", (p->mode == PIPE_OPAQUE) ? '-' : '=', p->peer->name);
+}
+
 
 struct protocol proto_pipe = {
   name:                "Pipe",
@@ -195,5 +202,6 @@ struct protocol proto_pipe = {
   start:       pipe_start,
   cleanup:     pipe_cleanup,
   reconfigure: pipe_reconfigure,
+  copy_config:  pipe_copy_config,
   get_status:  pipe_get_status,
 };
index 01cb6899d15812290c467b5d6378314193ecb5a1..42d4bff92eb9cfaec884e88c1184cec304f60e73 100644 (file)
@@ -318,6 +318,19 @@ radv_reconfigure(struct proto *p, struct proto_config *c)
   return 1;
 }
 
+static void
+radv_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+  struct radv_config *d = (struct radv_config *) dest;
+  struct radv_config *s = (struct radv_config *) src;
+
+  /* We clean up patt_list, ifaces are non-sharable */
+  init_list(&d->patt_list);
+
+  /* We copy pref_list, shallow copy suffices */
+  cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct iface_patt));
+}
+
 
 struct protocol proto_radv = {
   .name =              "RAdv",
@@ -325,5 +338,6 @@ struct protocol proto_radv = {
   .init =              radv_init,
   .start =             radv_start,
   .shutdown =          radv_shutdown,
-  .reconfigure =       radv_reconfigure
+  .reconfigure =       radv_reconfigure,
+  .copy_config =       radv_copy_config
 };
index fe121f2677a5a06e4c9aaffdc73caa79c030fd88..12bfe42e5104d8b5a69ebe579d33280c635bc296 100644 (file)
 struct radv_config
 {
   struct proto_config c;
-  list patt_list;              /* List of iface configs */
-  list pref_list;              /* Global list of prefix configs */
+  list patt_list;              /* List of iface configs (struct radv_iface_config) */
+  list pref_list;              /* Global list of prefix configs (struct radv_prefix_config) */
 };
 
 struct radv_iface_config
 {
   struct iface_patt i;
-  list pref_list;              /* Local list of prefix configs */
+  list pref_list;              /* Local list of prefix configs (struct radv_prefix_config) */
 
   u32 min_ra_int;              /* Standard options from RFC 4261 */
   u32 max_ra_int;
@@ -64,7 +64,7 @@ struct radv_iface_config
   u32 link_mtu;
   u32 reachable_time;
   u32 retrans_timer;
-  u32 current_hop_limit;               
+  u32 current_hop_limit;
   u32 default_lifetime;
 };
 
index 2df0c5c86d0d96971032a8776c62b5e002c1f3b9..cd4f30e7c0abd202acfa7fbf89d6bf7a09606f95 100644 (file)
@@ -37,7 +37,7 @@ CF_GRAMMAR
 CF_ADDTO(proto, rip_cfg '}' { RIP_CFG->passwords = get_passwords(); } )
 
 rip_cfg_start: proto_start RIP {
-     this_proto = proto_config_new(&proto_rip, sizeof(struct rip_proto_config));
+     this_proto = proto_config_new(&proto_rip, sizeof(struct rip_proto_config), $1);
      rip_init_config(RIP_CFG);
    }
  ;
index 1266380d8db7cff2df013255ef3278a53ed9dbf6..543aa30695d9501a1d65d5da81602798a140e8f4 100644 (file)
@@ -1015,6 +1015,19 @@ rip_reconfigure(struct proto *p, struct proto_config *c)
                  sizeof(struct rip_proto_config) - generic);
 }
 
+static void
+rip_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+  /* Shallow copy of everything */
+  proto_copy_rest(dest, src, sizeof(struct rip_proto_config));
+
+  /* We clean up iface_list, ifaces are non-sharable */
+  init_list(&((struct rip_proto_config *) dest)->iface_list);
+
+  /* Copy of passwords is OK, it just will be replaced in dest when used */
+}
+
+
 struct protocol proto_rip = {
   name: "RIP",
   template: "rip%d",
@@ -1026,4 +1039,5 @@ struct protocol proto_rip = {
   dump: rip_dump,
   start: rip_start,
   reconfigure: rip_reconfigure,
+  copy_config: rip_copy_config
 };
index 77d2419f1957e6e398064e5a5d41b64a54f672a2..621fdf9b95df1f0f586435a6f14a46ece4d8cc52 100644 (file)
@@ -26,7 +26,7 @@ CF_GRAMMAR
 CF_ADDTO(proto, static_proto '}')
 
 static_proto_start: proto_start STATIC {
-     this_proto = proto_config_new(&proto_static, sizeof(struct static_config));
+     this_proto = proto_config_new(&proto_static, sizeof(struct static_config), $1);
      static_init_config((struct static_config *) this_proto);
   }
  ;
index 2f33d817c53330deebfa200294a898324b45174f..e5b293c07ce5d8cf9bfd5218f6b87ead22597c7f 100644 (file)
@@ -470,6 +470,58 @@ static_reconfigure(struct proto *p, struct proto_config *new)
   return 1;
 }
 
+static void
+static_copy_routes(list *dlst, list *slst)
+{
+  struct static_route *dr, *sr;
+
+  init_list(dlst);
+  WALK_LIST(sr, *slst)
+    {
+      /* copy one route */
+      dr = cfg_alloc(sizeof(struct static_route));
+      memcpy(dr, sr, sizeof(struct static_route));
+
+      /* This fn is supposed to be called on fresh src routes, which have 'live'
+        fields (like .chain, .neigh or .installed) zero, so no need to zero them */
+
+      /* We need to copy multipath chain, because there are backptrs in 'if_name' */
+      if (dr->dest == RTD_MULTIPATH)
+       {
+         struct static_route *md, *ms, **mp_last;
+
+         mp_last = &(dr->mp_next);
+         for (ms = sr->mp_next; ms; ms = ms->mp_next)
+           {
+             md = cfg_alloc(sizeof(struct static_route));
+             memcpy(md, ms, sizeof(struct static_route));
+             md->if_name = (void *) dr; /* really */
+
+             *mp_last = md;
+             mp_last = &(md->mp_next);
+           }
+         *mp_last = NULL;
+       }
+
+      add_tail(dlst, (node *) dr);
+    }
+}
+
+static void
+static_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+  struct static_config *d = (struct static_config *) dest;
+  struct static_config *s = (struct static_config *) src;
+
+  /* Shallow copy of everything */
+  proto_copy_rest(dest, src, sizeof(struct static_config));
+
+  /* Copy route lists */
+  static_copy_routes(&d->iface_routes, &s->iface_routes);
+  static_copy_routes(&d->other_routes, &s->other_routes);
+}
+
+
 struct protocol proto_static = {
   name:                "Static",
   template:    "static%d",
@@ -479,6 +531,7 @@ struct protocol proto_static = {
   shutdown:    static_shutdown,
   cleanup:     static_cleanup,
   reconfigure: static_reconfigure,
+  copy_config: static_copy_config
 };
 
 static void
index 7d96fe88ca37103b4f042916f353066a6799169e..7f0d52bdcae3364e493642fa55fa19e43dec4df2 100644 (file)
 /*
  *  We don't have split iface/scan/set parts. See krt-sock.h.
  */
+
+struct krt_if_params {
+};
+
+struct krt_if_status {
+};
+
 static inline int kif_params_same(struct krt_if_params *old UNUSED, struct krt_if_params *new UNUSED) { return 1; }
+static inline void kif_copy_params(struct krt_if_params *dest UNUSED, struct krt_if_params *src UNUSED) { }
 
 #endif
index 284df5ea84c5903fc1cbee13a34745d86f0cf44d..19cd930d602796cb4494b9d5245e783c75a6cac0 100644 (file)
@@ -17,5 +17,6 @@ struct krt_scan_status {
 };
 
 static inline int krt_scan_params_same(struct krt_scan_params *o UNUSED, struct krt_scan_params *n UNUSED) { return 1; }
+static inline void krt_scan_copy_params(struct krt_scan_params *d UNUSED, struct krt_scan_params *s UNUSED) { }
 
 #endif
index d2a7efbc1c8af7d6730bab4e1594ad2957d5cba5..aab639c4e6d054c1d3368dd6debad3c8da833001 100644 (file)
@@ -34,13 +34,9 @@ struct krt_set_params {
 struct krt_set_status {
 };
 
-struct krt_if_params {
-};
-
-struct krt_if_status {
-};
-
 static inline int krt_set_params_same(struct krt_set_params *o UNUSED, struct krt_set_params *n UNUSED) { return 1; }
+static inline void krt_set_copy_params(struct krt_set_params *d UNUSED, struct krt_set_params *s UNUSED) { }
+
 void krt_read_msg(struct proto *p, struct ks_msg *msg, int scan);
 
 #endif
index f44ca27f8f39bf93930896bc6f54085d5f601d32..770c6e2efcec5444a020929668a195f6e72fa6ef 100644 (file)
@@ -24,5 +24,6 @@ static inline void krt_if_shutdown(struct kif_proto *p UNUSED) { };
 static inline void krt_if_io_init(void) { };
 
 static inline int kif_params_same(struct krt_if_params *old UNUSED, struct krt_if_params *new UNUSED) { return 1; }
+static inline void kif_copy_params(struct krt_if_params *dest UNUSED, struct krt_if_params *src UNUSED) { }
 
 #endif
index 7885f078d602b72807c47116d7e904c311f79b89..9b5e075b842cce704aada3a1b8fa06b1e064139e 100644 (file)
@@ -30,4 +30,7 @@ static inline int krt_scan_params_same(struct krt_scan_params *o, struct krt_sca
   return o->table_id == n->table_id;
 }
 
+static inline void krt_scan_copy_params(struct krt_scan_params *d UNUSED, struct krt_scan_params *s UNUSED) { }
+/* table_id copied in krt_copy_config() */
+
 #endif
index 83d082d0dcb707d35c20d6c8d27b5d51bb412a5a..4a08217ba6a9101e117baec8191acb0ac03b95e2 100644 (file)
@@ -23,5 +23,6 @@ static inline void krt_set_construct(struct krt_config *c UNUSED) { };
 static inline void krt_set_start(struct krt_proto *p UNUSED, int first UNUSED) { };
 static inline void krt_set_shutdown(struct krt_proto *p UNUSED, int last UNUSED) { };
 static inline int krt_set_params_same(struct krt_set_params *o UNUSED, struct krt_set_params *n UNUSED) { return 1; }
+static inline void krt_set_copy_params(struct krt_set_params *d UNUSED, struct krt_set_params *s UNUSED) { }
 
 #endif
index 48075d6b0d612b9335d914e60928f36e779e6e9f..9e12bcc3d4b7eac983e1a187dadf99ebf6579d60 100644 (file)
@@ -17,6 +17,7 @@ struct krt_if_status {
 
 extern int if_scan_sock;
 
-static inline int kif_params_same(struct krt_if_params *old, struct krt_if_params *new) { return 1; }
+static inline int kif_params_same(struct krt_if_params *old UNUSED, struct krt_if_params *new UNUSED) { return 1; }
+static inline void kif_copy_params(struct krt_if_params *dest UNUSED, struct krt_if_params *src UNUSED) { }
 
 #endif
index 5d0b213497254a96b9e6c952442c11dbb152f662..87cffcfc6c1c015d22fbd6b57f60d83743a1eb50 100644 (file)
@@ -16,5 +16,6 @@ struct krt_set_status {
 };
 
 static inline int krt_set_params_same(struct krt_set_params *o UNUSED, struct krt_set_params *n UNUSED) { return 1; }
+static inline void krt_set_copy_params(struct krt_set_params *d UNUSED, struct krt_set_params *s UNUSED) { }
 
 #endif
index 0375a13b53d50d21e7b2d75c3520d2c8198f0d21..86081966a21e888181713224a154ccb1fb676255 100644 (file)
@@ -30,7 +30,7 @@ kern_proto_start: proto_start KERNEL {
      if (cf_krt)
        cf_error("Kernel protocol already defined");
 #endif
-     cf_krt = this_proto = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config));
+     cf_krt = this_proto = proto_config_new(&proto_unix_kernel, sizeof(struct krt_config), $1);
      this_proto->preference = DEF_PREF_INHERITED;
      THIS_KRT->scan_time = 60;
      THIS_KRT->learn = THIS_KRT->persist = 0;
@@ -66,7 +66,7 @@ CF_ADDTO(proto, kif_proto '}')
 kif_proto_start: proto_start DEVICE {
      if (cf_kif)
        cf_error("Kernel device protocol already defined");
-     cf_kif = this_proto = proto_config_new(&proto_unix_iface, sizeof(struct kif_config));
+     cf_kif = this_proto = proto_config_new(&proto_unix_iface, sizeof(struct kif_config), $1);
      this_proto->preference = DEF_PREF_DIRECT;
      THIS_KIF->scan_time = 60;
      init_list(&THIS_KIF->primary);
index 7057070385b261c452f517eca985091100927272..e5a8ce1758c22ad193bf00e641f282413fe49125 100644 (file)
@@ -216,6 +216,23 @@ kif_reconfigure(struct proto *p, struct proto_config *new)
   return 1;
 }
 
+static void
+kif_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+  struct kif_config *d = (struct kif_config *) dest;
+  struct kif_config *s = (struct kif_config *) src;
+
+  /* Shallow copy of everything (just scan_time currently) */
+  proto_copy_rest(dest, src, sizeof(struct krt_config));
+
+  /* Copy primary addr list */
+  cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item));
+
+  /* Fix sysdep parts */
+  kif_copy_params(&d->iface, &s->iface);
+}
+
+
 struct protocol proto_unix_iface = {
   name:                "Device",
   template:    "device%d",
@@ -224,6 +241,7 @@ struct protocol proto_unix_iface = {
   start:       kif_start,
   shutdown:    kif_shutdown,
   reconfigure: kif_reconfigure,
+  copy_config: kif_copy_config
 };
 
 /*
@@ -908,6 +926,19 @@ krt_reconfigure(struct proto *p, struct proto_config *new)
     ;
 }
 
+static void
+krt_copy_config(struct proto_config *dest, struct proto_config *src)
+{
+  struct krt_config *d = (struct krt_config *) dest;
+  struct krt_config *s = (struct krt_config *) src;
+
+  /* Shallow copy of everything */
+  proto_copy_rest(dest, src, sizeof(struct krt_config));
+
+  /* Fix sysdep parts */
+  krt_set_copy_params(&d->set, &s->set);
+  krt_scan_copy_params(&d->scan, &s->scan);
+}
 
 static int
 krt_get_attr(eattr * a, byte * buf, int buflen UNUSED)
@@ -936,6 +967,7 @@ struct protocol proto_unix_kernel = {
   start:       krt_start,
   shutdown:    krt_shutdown,
   reconfigure: krt_reconfigure,
+  copy_config: krt_copy_config,
   get_attr:    krt_get_attr,
 #ifdef KRT_ALLOW_LEARN
   dump:                krt_dump,
index f83e6ee67a6c63778d902dfe95f6310135198cb5..7bb4fe702100012c40d6bf22d813c1fe29d6ab7b 100644 (file)
@@ -100,7 +100,7 @@ struct kif_config {
   struct proto_config c;
   struct krt_if_params iface;
   int scan_time;               /* How often we re-scan interfaces */
-  list primary;                        /* Preferences for primary addresses */
+  list primary;                        /* Preferences for primary addresses (struct kif_primary_item) */
 };
 
 struct kif_proto {