]> git.ipfire.org Git - thirdparty/bird.git/blobdiff - proto/rip/config.Y
RIP: Demand circuit support (RFC 2091)
[thirdparty/bird.git] / proto / rip / config.Y
index a3e877dac6955e8ba106d08eb2312b7c018ca2d5..6cea7dd0a62e8943973b399f04a16cf44a3e04d3 100644 (file)
 /*
  *     BIRD -- RIP Configuration
  *
+ *     (c) 1998--1999 Pavel Machek <pavel@ucw.cz>
+ *     (c) 2004--2013 Ondrej Filip <feela@network.cz>
+ *     (c) 2009--2015 Ondrej Zajicek <santiago@crfreenet.org>
+ *     (c) 2009--2015 CZ.NIC z.s.p.o.
+ *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
 
-/*
-To add:
-
-version1 switch
-
-*/
-
-
 CF_HDR
 
 #include "proto/rip/rip.h"
 #include "nest/iface.h"
 
-void rip_dev_add_iface(char *);
-struct rip_patt *rip_get_iface(void);
+CF_DEFINES
+
+#define RIP_CFG ((struct rip_config *) this_proto)
+#define RIP_IFACE ((struct rip_iface_config *) this_ipatt)
+
+static inline int rip_cfg_is_v2(void) { return RIP_CFG->rip2; }
+static inline int rip_cfg_is_ng(void) { return ! RIP_CFG->rip2; }
+
+static inline void
+rip_check_auth(void)
+{
+  if (rip_cfg_is_ng())
+    cf_error("Authentication not supported in RIPng");
+}
 
-#define RIP_CFG ((struct rip_proto_config *) this_proto)
 
 CF_DECLS
 
-CF_KEYWORDS(RIP, INFINITY, METRIC, PORT, PERIOD, GARBAGETIME, PASSWORDS,
-           MODE, BROADCAST, QUIET, NOLISTEN, VERSION1, 
-           AUTHENTICATION, NONE, PLAINTEXT, MD5)
+CF_KEYWORDS(RIP, NG, ECMP, LIMIT, WEIGHT, INFINITY, METRIC, UPDATE, TIMEOUT,
+           GARBAGE, PORT, ADDRESS, MODE, BROADCAST, MULTICAST, PASSIVE,
+           VERSION, SPLIT, HORIZON, POISON, REVERSE, CHECK, ZERO, TIME, BFD,
+           AUTHENTICATION, NONE, PLAINTEXT, CRYPTOGRAPHIC, MD5, TTL, SECURITY,
+           RX, TX, BUFFER, LENGTH, PRIORITY, ONLY, LINK, DEMAND, CIRCUIT,
+           RIP_METRIC, RIP_TAG)
 
-%type <i> rip_mode rip_auth
+%type <i> rip_variant rip_auth
 
 CF_GRAMMAR
 
-CF_ADDTO(proto, RIP_CFG '}')
+proto: rip_proto ;
 
-RIP_CFG_start: proto_start RIP {
-     RIP_CFG = proto_config_new(&proto_rip, sizeof(struct rip_proto_config));
-     rip_init_config(RIP_CFG);
-   }
+rip_variant:
+   RIP    { $$ = 1; }
+ | RIP NG { $$ = 0; }
  ;
 
-RIP_CFG:
-   RIP_CFG_start proto_name '{'
- | RIP_CFG proto_item ';'
- | RIP_CFG INFINITY expr ';'   { RIP_CFG->infinity = $3; }
- | RIP_CFG PORT expr ';'       { RIP_CFG->port = $3; }
- | RIP_CFG PERIOD expr ';'     { RIP_CFG->period = $3; }
- | RIP_CFG GARBAGETIME expr ';' { RIP_CFG->garbage_time = $3; }
- | RIP_CFG AUTHENTICATION rip_auth ';' {RIP_CFG->authtype = $3; }
- | RIP_CFG PASSWORDS '{' password_list '}' {RIP_CFG->passwords = $4; }
- | RIP_CFG rip_iface_list ';'
+rip_proto_start: proto_start rip_variant
+{
+  this_proto = proto_config_new(&proto_rip, $1);
+  this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
+
+  init_list(&RIP_CFG->patt_list);
+  RIP_CFG->rip2 = $2;
+  RIP_CFG->ecmp = rt_default_ecmp;
+  RIP_CFG->infinity = RIP_DEFAULT_INFINITY;
+  RIP_CFG->min_timeout_time = 60 S_;
+  RIP_CFG->max_garbage_time = 60 S_;
+};
+
+rip_proto_item:
+   proto_item
+ | proto_channel
+ | ECMP bool           { RIP_CFG->ecmp = $2 ? RIP_DEFAULT_ECMP_LIMIT : 0; }
+ | ECMP bool LIMIT expr        { RIP_CFG->ecmp = $2 ? $4 : 0; }
+ | INFINITY expr       { RIP_CFG->infinity = $2; }
+ | INTERFACE rip_iface
  ;
 
-rip_auth:
-   PLAINTEXT { $$=AT_PLAINTEXT; }
- | MD5 { $$=AT_MD5; }
- | NONE { $$=AT_NONE; }
+rip_proto_opts:
+   /* empty */
+ | rip_proto_opts rip_proto_item ';'
  ;
 
-rip_mode: 
-    BROADCAST { $$|=IM_BROADCAST; }
-  | QUIET     { $$|=IM_QUIET; }
-  | NOLISTEN  { $$|=IM_NOLISTEN; }
-  | VERSION1  { $$|=IM_VERSION1 | IM_BROADCAST; }
- ;
+rip_proto:
+   rip_proto_start proto_name '{' rip_proto_opts '}';
+
+
+rip_iface_start:
+{
+  this_ipatt = cfg_allocz(sizeof(struct rip_iface_config));
+  add_tail(&RIP_CFG->patt_list, NODE this_ipatt);
+  init_list(&this_ipatt->ipn_list);
+  reset_passwords();
+
+  RIP_IFACE->metric = 1;
+  RIP_IFACE->port = rip_cfg_is_v2() ? RIP_PORT : RIP_NG_PORT;
+  RIP_IFACE->version = rip_cfg_is_v2() ? RIP_V2 : RIP_V1;
+  RIP_IFACE->split_horizon = 1;
+  RIP_IFACE->poison_reverse = 1;
+  RIP_IFACE->check_zero = 1;
+  RIP_IFACE->check_link = 1;
+  RIP_IFACE->ttl_security = rip_cfg_is_v2() ? 0 : 1;
+  RIP_IFACE->rx_buffer = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0;
+  RIP_IFACE->tx_length = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0;
+  RIP_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL;
+  RIP_IFACE->tx_priority = sk_priority_control;
+  RIP_IFACE->update_time = RIP_DEFAULT_UPDATE_TIME;
+  RIP_IFACE->timeout_time = RIP_DEFAULT_TIMEOUT_TIME;
+  RIP_IFACE->garbage_time = RIP_DEFAULT_GARBAGE_TIME;
+  RIP_IFACE->rxmt_time = RIP_DEFAULT_RXMT_TIME;
+};
+
+rip_iface_finish:
+{
+  /* Default mode is broadcast for RIPv1, multicast for RIPv2 and RIPng */
+  if (!RIP_IFACE->mode)
+    RIP_IFACE->mode = (rip_cfg_is_v2() && (RIP_IFACE->version == RIP_V1)) ?
+      RIP_IM_BROADCAST : RIP_IM_MULTICAST;
+
+  RIP_IFACE->passwords = get_passwords();
+
+  if (!RIP_IFACE->auth_type != !RIP_IFACE->passwords)
+    log(L_WARN "Authentication and password options should be used together");
+
+  if (RIP_IFACE->passwords)
+  {
+    struct password_item *pass;
+    WALK_LIST(pass, *RIP_IFACE->passwords)
+    {
+      if (pass->alg && (RIP_IFACE->auth_type != RIP_AUTH_CRYPTO))
+       cf_error("Password algorithm option requires cryptographic authentication");
+
+      /* Set default crypto algorithm (MD5) */
+      if (!pass->alg && (RIP_IFACE->auth_type == RIP_AUTH_CRYPTO))
+       pass->alg = ALG_MD5;
+    }
+  }
+
+  RIP_CFG->min_timeout_time = MIN_(RIP_CFG->min_timeout_time, RIP_IFACE->timeout_time);
+  RIP_CFG->max_garbage_time = MAX_(RIP_CFG->max_garbage_time, RIP_IFACE->garbage_time);
+};
 
 rip_iface_item:
- | METRIC expr { 
-   struct rip_patt *k = rip_get_iface();
-   k->metric = $2;
- }
- | MODE rip_mode {
-   struct rip_patt *k = rip_get_iface();
-   k->mode = $2;
- }
+   METRIC expr         { RIP_IFACE->metric = $2; if (($2<1) || ($2>255)) cf_error("Metric must be in range 1-255"); }
+ | MODE MULTICAST      { RIP_IFACE->mode = RIP_IM_MULTICAST; }
+ | MODE BROADCAST      { RIP_IFACE->mode = RIP_IM_BROADCAST; if (rip_cfg_is_ng()) cf_error("Broadcast not supported in RIPng"); }
+ | PASSIVE bool                { RIP_IFACE->passive = $2; }
+ | ADDRESS ipa         { RIP_IFACE->address = $2; if (ipa_is_ip4($2) != rip_cfg_is_v2()) cf_error("IP address version mismatch"); }
+ | PORT expr           { RIP_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
+ | VERSION expr                { RIP_IFACE->version = $2;
+                         if (rip_cfg_is_ng()) cf_error("Version not supported in RIPng");
+                         if (($2 != RIP_V1) && ($2 != RIP_V2)) cf_error("Unsupported version");
+                       }
+ | VERSION ONLY bool   { RIP_IFACE->version_only = $3; }
+ | SPLIT HORIZON bool  { RIP_IFACE->split_horizon = $3; }
+ | POISON REVERSE bool { RIP_IFACE->poison_reverse = $3; }
+ | CHECK ZERO bool     { RIP_IFACE->check_zero = $3; }
+ | DEMAND CIRCUIT bool { RIP_IFACE->demand_circuit = $3; }
+ | UPDATE TIME expr    { RIP_IFACE->update_time = $3 S_; if ($3<=0) cf_error("Update time must be positive"); }
+ | TIMEOUT TIME expr   { RIP_IFACE->timeout_time = $3 S_; if ($3<=0) cf_error("Timeout time must be positive"); }
+ | GARBAGE TIME expr   { RIP_IFACE->garbage_time = $3 S_; if ($3<=0) cf_error("Garbage time must be positive"); }
+ | RETRANSMIT TIME expr_us { RIP_IFACE->rxmt_time = $3; if ($3<=0) cf_error("Retransmit time must be positive"); }
+ | ECMP WEIGHT expr    { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
+ | RX BUFFER expr      { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX length must be in range 256-65535"); }
+ | TX LENGTH expr      { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
+ | TX tos              { RIP_IFACE->tx_tos = $2; }
+ | TX PRIORITY expr    { RIP_IFACE->tx_priority = $3; }
+ | TTL SECURITY bool   { RIP_IFACE->ttl_security = $3; }
+ | TTL SECURITY TX ONLY        { RIP_IFACE->ttl_security = 2; }
+ | CHECK LINK bool     { RIP_IFACE->check_link = $3; }
+ | BFD bool            { RIP_IFACE->bfd = $2; cf_check_bfd($2); }
+ | AUTHENTICATION rip_auth { RIP_IFACE->auth_type = $2; if ($2) rip_check_auth(); }
+ | password_list       { rip_check_auth(); }
+;
+
+rip_auth:
+   NONE                        { $$ = RIP_AUTH_NONE; }
+ | PLAINTEXT           { $$ = RIP_AUTH_PLAIN; }
+ | CRYPTOGRAPHIC       { $$ = RIP_AUTH_CRYPTO; }
+ | MD5                 { $$ = RIP_AUTH_CRYPTO; }       /* For backward compatibility */
  ;
 
-rip_iface_opts: 
-   '{'
+rip_iface_opts:
+   /* empty */
  | rip_iface_opts rip_iface_item ';'
  ;
 
-rip_iface_empty: /* EMPTY */ | rip_iface_opts '}' ;
-
-rip_iface_list:
-   INTERFACE TEXT rip_iface_empty { rip_dev_add_iface($2); }
- | dev_iface_list ',' TEXT rip_iface_empty { rip_dev_add_iface($3); }
+rip_iface_opt_list:
+   /* empty */
+ | '{' rip_iface_opts '}'
  ;
 
-CF_CODE
+rip_iface:
+  rip_iface_start iface_patt_list_nopx rip_iface_opt_list rip_iface_finish;
 
-void
-rip_dev_add_iface(char *n)
-{
-  struct rip_patt *k = cfg_alloc(sizeof(struct rip_patt));
 
-  k->i.pattern = cfg_strdup(n);
-  add_tail(&RIP_CFG->iface_list, &k->i.n);
-}
+dynamic_attr: RIP_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_METRIC); } ;
+dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_TAG); } ;
 
-struct rip_patt *
-rip_get_iface(void)
-{
-  struct rip_patt *k = TAIL(RIP_CFG->iface_list);
-  if (!k)
-    cf_error( "This cannot happen" );
-  return k;
-}
+CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]);
+
+CF_CLI(SHOW RIP INTERFACES, optproto opttext, [<name>] [\"<interface>\"], [[Show information about RIP interfaces]])
+{ rip_show_interfaces(proto_get_named($4, &proto_rip), $5); };
 
+CF_CLI(SHOW RIP NEIGHBORS, optproto opttext, [<name>] [\"<interface>\"], [[Show information about RIP neighbors]])
+{ rip_show_neighbors(proto_get_named($4, &proto_rip), $5); };
+
+
+CF_CODE
 
 CF_END