]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
VPN4 and VPN6 literals
authorJan Moskyto Matejka <mq@ucw.cz>
Tue, 9 Feb 2016 13:53:29 +0000 (14:53 +0100)
committerJan Moskyto Matejka <mq@ucw.cz>
Thu, 7 Apr 2016 08:08:43 +0000 (10:08 +0200)
From now on, protocol static accepts VPN4 and VPN6 addressess.
With some concerns about VPN6 Route Distinguishers, I finally chose
to have the same format as for VPN4 (where it is defined by RFC 4364).

conf/cf-lex.l
conf/confbase.Y
lib/net.c

index ccf5826af24d8c202f40dad8dabe606ed83bd2ab..3848718d99dfeb7340ced948183f51937e9f5855 100644 (file)
@@ -122,6 +122,38 @@ include   ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
   cf_include(start, end-start);
 }
 
+[02]:{DIGIT}+:{DIGIT}+ {
+  char *e;
+  unsigned long int l;
+  cf_lval.i64 = ((u64)(yytext[0] - '0')) << 48;
+  errno = 0;
+  l = strtoul(yytext+2, &e, 10);
+  if (e && (*e != ':') || errno == ERANGE || (yytext[0] == '0') && (l >= (1<<16)))
+    cf_error("ASN out of range");
+  cf_lval.i64 |= (((u64) l) << 32);
+  errno = 0;
+  l = strtoul(e+1, &e, 10);
+  if (e && *e || errno == ERANGE || (yytext[0] == '2') && (l >= (1<<16)))
+    cf_error("Assigned number out of range");
+  cf_lval.i64 |= l;
+  return VPN_RD;
+}
+
+1:{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+:{DIGIT}+ {
+  unsigned long int l;
+  char *e = strchr(yytext+2, ':');
+  *e++ = '\0';
+  ip4_addr ip4;
+  if (!ip4_pton(yytext+2, &ip4))
+    cf_error("Invalid IPv4 address %s in Route Distinguisher", yytext+2);
+  errno = 0;
+  l = strtoul(e, &e, 10);
+  if (e && *e || errno == ERANGE || (l >= (1<<16)))
+    cf_error("Assigned number out of range");
+  cf_lval.i64 = (1ULL<<48) | (((u64)ip4_to_u32(ip4)) << 16) | ((u64)l);
+  return VPN_RD;
+}
+
 {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
   if (!ip4_pton(yytext, &cf_lval.ip4))
     cf_error("Invalid IPv4 address %s", yytext);
index 22aee77075d1b477deb2b758834f72e2bbfe34b7..768e4c7049c02b6e0d430da5215a7f3dd58814bb 100644 (file)
@@ -38,6 +38,7 @@ CF_DECLS
 %union {
   int i;
   u32 i32;
+  u64 i64;
   ip_addr a;
   ip4_addr ip4;
   ip6_addr ip6;
@@ -72,6 +73,7 @@ CF_DECLS
 %token <i> NUM ENUM
 %token <ip4> IP4
 %token <ip6> IP6
+%token <i64> VPN_RD
 %token <s> SYM
 %token <t> TEXT
 %type <iface> ipa_scope
@@ -81,7 +83,7 @@ CF_DECLS
 %type <time> datetime
 %type <a> ipa
 %type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
-%type <net_ptr> net_ net_any net_roa4_ net_roa6_ net_roa_
+%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_
 
 %type <t> text opttext
 
@@ -93,7 +95,7 @@ CF_DECLS
 %left '!'
 %nonassoc '.'
 
-CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT)
+CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN)
 
 CF_GRAMMAR
 
@@ -198,6 +200,18 @@ net_ip6_: IP6 '/' NUM
     cf_error("Invalid IPv6 prefix");
 };
 
+net_vpn4_: VPN_RD net_ip4_
+{
+  $$ = cfg_alloc(sizeof(net_addr_vpn4));
+  net_fill_vpn4($$, ((net_addr_ip4 *)&$2)->prefix, $2.pxlen, $1);
+}
+
+net_vpn6_: VPN_RD net_ip6_
+{
+  $$ = cfg_alloc(sizeof(net_addr_vpn6));
+  net_fill_vpn6($$, ((net_addr_ip6 *)&$2)->prefix, $2.pxlen, $1);
+}
+
 net_roa4_: net_ip4_ MAX NUM AS NUM
 {
   $$ = cfg_alloc(sizeof(net_addr_roa4));
@@ -220,9 +234,11 @@ net_roa6_: net_ip6_ MAX NUM AS NUM
 
 net_ip_: net_ip4_ | net_ip6_ ;
 net_roa_: net_roa4_ | net_roa6_ ;
+net_vpn_: net_vpn4_ | net_vpn6_ ;
 
 net_:
    net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
+ | net_vpn_
  | net_roa_
  ;
 
index 2561243abd3d8b2b8861d1afa4ee8a1f1b713c3f..85a2f1ad59d45e13a7405b5a1e403e50d5884d0d 100644 (file)
--- a/lib/net.c
+++ b/lib/net.c
@@ -51,9 +51,23 @@ net_format(const net_addr *N, char *buf, int buflen)
   case NET_IP6:
     return bsnprintf(buf, buflen, "%I6/%d", n->ip6.prefix, n->ip6.pxlen);
   case NET_VPN4:
-    return bsnprintf(buf, buflen, "%u:%u %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen);
+    switch (n->vpn4.rd >> 48)
+    {
+      case 0: return bsnprintf(buf, buflen, "0:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen);
+      case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I4/%d", ip4_from_u32(n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen);
+      case 2: return bsnprintf(buf, buflen, "2:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen);
+    }
+    return 0;
+
+    /* XXX: RD format is specified for VPN4; not found any for VPN6, reusing the same as for VPN4. */
   case NET_VPN6:
-    return bsnprintf(buf, buflen, "%u:%u %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen);
+    switch (n->vpn4.rd >> 48)
+    {
+      case 0: return bsnprintf(buf, buflen, "0:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen);
+      case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I6/%d", ip4_from_u32(n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen);
+      case 2: return bsnprintf(buf, buflen, "2:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen);
+    }
+    return 0;
   case NET_ROA4:
     return bsnprintf(buf, buflen, "%I4/%u-%u AS%u",  n->roa4.prefix, n->roa4.pxlen, n->roa4.max_pxlen, n->roa4.asn);
   case NET_ROA6: