]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Merge commit '76baa8b38ad411e871793ab30bb94e17e1cd2397' into pim
authorOndrej Zajicek (work) <santiago@crfreenet.org>
Mon, 22 Jan 2018 20:09:29 +0000 (21:09 +0100)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Mon, 22 Jan 2018 20:09:29 +0000 (21:09 +0100)
12 files changed:
1  2 
lib/ip.h
lib/net.c
lib/net.h
lib/printf.c
lib/socket.h
nest/config.Y
nest/route.h
nest/rt-attr.c
nest/rt-fib.c
nest/rt-table.c
sysdep/linux/sysio.h
sysdep/unix/io.c

diff --cc lib/ip.h
index 5cfce1f18a7a15e3f232d3ddb2eff952dc51f92a,6541ce1ebd462714825c9616f3010faff7ecff6b..ec2d69668cc39782e566b732047b77a0561e7e66
+++ b/lib/ip.h
@@@ -238,6 -237,6 +238,12 @@@ static inline int ip6_is_link_local(ip6
  static inline int ip6_is_v4mapped(ip6_addr a)
  { return _I0(a) == 0 && _I1(a) == 0 && _I2(a) == 0xffff; }
  
++static inline int ip4_is_multicast(ip4_addr a)
++{ return (_I(a)  & 0xf0000000) == 0xe0000000; }
++
++static inline int ip6_is_multicast(ip6_addr a)
++{ return (_I0(a) & 0xff000000) == 0xff000000; }
++
  #define ipa_classify(x) ip6_classify(&(x))
  #define ipa_is_link_local(x) ip6_is_link_local(x)
  
diff --cc lib/net.c
index 9335b78f5ece5172d0261ee3ed3a803ab15ea60f,0e7262b2a6599234418d53c4a91cd7b4067192b1..01af3a4d1694157a446bd53910e91348995d3899
+++ b/lib/net.c
@@@ -6,51 -5,55 +6,67 @@@
  
  
  const char * const net_label[] = {
 -  [NET_IP4] = "ipv4",
 -  [NET_IP6] = "ipv6",
 -  [NET_VPN4] = "vpn4",
 -  [NET_VPN6] = "vpn6",
 -  [NET_ROA4] = "roa4",
 -  [NET_ROA6] = "roa6",
 -  [NET_MREQ4] = "mreq4",
 -  [NET_MREQ6] = "mreq6",
 -  [NET_MGRP4] = "mgrp4",
 -  [NET_MGRP6] = "mgrp6",
 +  [NET_IP4]   = "ipv4",
 +  [NET_IP6]   = "ipv6",
 +  [NET_VPN4]  = "vpn4",
 +  [NET_VPN6]  = "vpn6",
 +  [NET_ROA4]  = "roa4",
 +  [NET_ROA6]  = "roa6",
-   [NET_FLOW4]         = "flow4",
-   [NET_FLOW6]         = "flow6",
++  [NET_FLOW4] = "flow4",
++  [NET_FLOW6] = "flow6",
++  [NET_MREQ4] = "mreq4",
++  [NET_MREQ6] = "mreq6",
++  [NET_MGRP4] = "mgrp4",
++  [NET_MGRP6] = "mgrp6",
 +  [NET_MPLS]  = "mpls",
  };
  
  const u16 net_addr_length[] = {
 -  [NET_IP4] = sizeof(net_addr_ip4),
 -  [NET_IP6] = sizeof(net_addr_ip6),
 -  [NET_VPN4] = sizeof(net_addr_vpn4),
 -  [NET_VPN6] = sizeof(net_addr_vpn6),
 -  [NET_ROA4] = sizeof(net_addr_roa4),
 -  [NET_ROA6] = sizeof(net_addr_roa6),
 -  [NET_MREQ4] = sizeof(net_addr_mreq4),
 -  [NET_MREQ6] = sizeof(net_addr_mreq6),
 -  [NET_MGRP4] = sizeof(net_addr_mgrp4),
 -  [NET_MGRP6] = sizeof(net_addr_mgrp6),
 +  [NET_IP4]   = sizeof(net_addr_ip4),
 +  [NET_IP6]   = sizeof(net_addr_ip6),
 +  [NET_VPN4]  = sizeof(net_addr_vpn4),
 +  [NET_VPN6]  = sizeof(net_addr_vpn6),
 +  [NET_ROA4]  = sizeof(net_addr_roa4),
 +  [NET_ROA6]  = sizeof(net_addr_roa6),
-   [NET_FLOW4]         = 0,
-   [NET_FLOW6]         = 0,
++  [NET_FLOW4] = 0,
++  [NET_FLOW6] = 0,
++  [NET_MREQ4] = sizeof(net_addr_mreq4),
++  [NET_MREQ6] = sizeof(net_addr_mreq6),
++  [NET_MGRP4] = sizeof(net_addr_mgrp4),
++  [NET_MGRP6] = sizeof(net_addr_mgrp6),
 +  [NET_MPLS]  = sizeof(net_addr_mpls),
  };
  
  const u8 net_max_prefix_length[] = {
 -  [NET_IP4] = IP4_MAX_PREFIX_LENGTH,
 -  [NET_IP6] = IP6_MAX_PREFIX_LENGTH,
 -  [NET_VPN4] = IP4_MAX_PREFIX_LENGTH,
 -  [NET_VPN6] = IP6_MAX_PREFIX_LENGTH,
 -  [NET_ROA4] = IP4_MAX_PREFIX_LENGTH,
 -  [NET_ROA6] = IP6_MAX_PREFIX_LENGTH,
 -  [NET_MREQ4] = IP4_MAX_PREFIX_LENGTH,
 -  [NET_MREQ6] = IP6_MAX_PREFIX_LENGTH,
 -  [NET_MGRP4] = IP4_MAX_PREFIX_LENGTH,
 -  [NET_MGRP6] = IP6_MAX_PREFIX_LENGTH,
 +  [NET_IP4]   = IP4_MAX_PREFIX_LENGTH,
 +  [NET_IP6]   = IP6_MAX_PREFIX_LENGTH,
 +  [NET_VPN4]  = IP4_MAX_PREFIX_LENGTH,
 +  [NET_VPN6]  = IP6_MAX_PREFIX_LENGTH,
 +  [NET_ROA4]  = IP4_MAX_PREFIX_LENGTH,
 +  [NET_ROA6]  = IP6_MAX_PREFIX_LENGTH,
-   [NET_FLOW4]         = IP4_MAX_PREFIX_LENGTH,
-   [NET_FLOW6]         = IP6_MAX_PREFIX_LENGTH,
++  [NET_FLOW4] = IP4_MAX_PREFIX_LENGTH,
++  [NET_FLOW6] = IP6_MAX_PREFIX_LENGTH,
++  [NET_MREQ4] = IP4_MAX_PREFIX_LENGTH,
++  [NET_MREQ6] = IP6_MAX_PREFIX_LENGTH,
++  [NET_MGRP4] = IP4_MAX_PREFIX_LENGTH,
++  [NET_MGRP6] = IP6_MAX_PREFIX_LENGTH,
 +  [NET_MPLS]  = 0,
  };
  
  const u16 net_max_text_length[] = {
 -  [NET_IP4] = 18,     /* "255.255.255.255/32" */
 -  [NET_IP6] = 43,     /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
 -  [NET_VPN4] = 40,    /* "4294967296:4294967296 255.255.255.255/32" */
 -  [NET_VPN6] = 65,    /* "4294967296:4294967296 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
 -  [NET_ROA4] = 34,      /* "255.255.255.255/32-32 AS4294967295" */
 -  [NET_ROA6] = 60,      /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */
 -  [NET_MREQ4] = 15,   /* "255.255.255.255" */
 -  [NET_MREQ6] = 39,   /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" */
 -  [NET_MGRP4] = 15,   /* "255.255.255.255" */
 -  [NET_MGRP6] = 39,   /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" */
 +  [NET_IP4]   = 18,   /* "255.255.255.255/32" */
 +  [NET_IP6]   = 43,   /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
 +  [NET_VPN4]  = 40,   /* "4294967296:4294967296 255.255.255.255/32" */
 +  [NET_VPN6]  = 65,   /* "4294967296:4294967296 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
 +  [NET_ROA4]  = 34,   /* "255.255.255.255/32-32 AS4294967295" */
 +  [NET_ROA6]  = 60,   /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */
-   [NET_FLOW4]         = 0,    /* "flow4 { ... }" */
-   [NET_FLOW6]         = 0,    /* "flow6 { ... }" */
++  [NET_FLOW4] = 0,    /* "flow4 { ... }" */
++  [NET_FLOW6] = 0,    /* "flow6 { ... }" */
++  [NET_MREQ4] = 15,   /* "255.255.255.255" */
++  [NET_MREQ6] = 39,   /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" */
++  [NET_MGRP4] = 15,   /* "255.255.255.255" */
++  [NET_MGRP6] = 39,   /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" */
 +  [NET_MPLS]  = 7,    /* "1048575" */
  };
  
  
@@@ -98,15 -76,15 +114,23 @@@ net_format(const net_addr *N, char *buf
      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:
      return bsnprintf(buf, buflen, "%I6/%u-%u AS%u",  n->roa6.prefix, n->roa6.pxlen, n->roa6.max_pxlen, n->roa6.asn);
 -  case NET_MGRP4:
 -    return bsnprintf(buf, buflen, "%I4", n->mgrp4.ga);
 +  case NET_FLOW4:
 +    return flow4_net_format(buf, buflen, &n->flow4);
 +  case NET_FLOW6:
 +    return flow6_net_format(buf, buflen, &n->flow6);
+   case NET_MREQ4:
 -    return bsnprintf(buf, buflen, "%I6", n->mgrp6.ga);
++    return bsnprintf(buf, buflen, "%I4", n->mreq4.grp);
+   case NET_MREQ6:
++    return bsnprintf(buf, buflen, "%I6", n->mreq6.grp);
++  case NET_MGRP4:
++    return bsnprintf(buf, buflen, "%I4", n->mgrp4.grp);
+   case NET_MGRP6:
++    return bsnprintf(buf, buflen, "%I6", n->mgrp6.grp);
 +  case NET_MPLS:
 +    return bsnprintf(buf, buflen, "%u", n->mpls.label);
    }
  
 -  return 0;
 +  bug("unknown network type");
  }
  
  ip_addr
@@@ -117,16 -95,17 +141,20 @@@ net_pxmask(const net_addr *a
    case NET_IP4:
    case NET_VPN4:
    case NET_ROA4:
 +  case NET_FLOW4:
+   case NET_MREQ4:
+   case NET_MGRP4:
      return ipa_from_ip4(ip4_mkmask(net4_pxlen(a)));
  
    case NET_IP6:
    case NET_VPN6:
    case NET_ROA6:
 +  case NET_FLOW6:
+   case NET_MREQ6:
+   case NET_MGRP6:
      return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
  
 +  case NET_MPLS:
    default:
      return IPA_NONE;
    }
@@@ -152,54 -131,40 +180,70 @@@ net_compare(const net_addr *a, const ne
      return net_compare_roa4((const net_addr_roa4 *) a, (const net_addr_roa4 *) b);
    case NET_ROA6:
      return net_compare_roa6((const net_addr_roa6 *) a, (const net_addr_roa6 *) b);
 -  case NET_MREQ6:
 +  case NET_FLOW4:
 +    return net_compare_flow4((const net_addr_flow4 *) a, (const net_addr_flow4 *) b);
 +  case NET_FLOW6:
 +    return net_compare_flow6((const net_addr_flow6 *) a, (const net_addr_flow6 *) b);
+   case NET_MREQ4:
++    return net_compare_mreq4((const net_addr_mreq4 *) a, (const net_addr_mreq4 *) b);
++  case NET_MREQ6:
++    return net_compare_mreq6((const net_addr_mreq6 *) a, (const net_addr_mreq6 *) b);
+   case NET_MGRP4:
+     return net_compare_mgrp4((const net_addr_mgrp4 *) a, (const net_addr_mgrp4 *) b);
+   case NET_MGRP6:
+     return net_compare_mgrp6((const net_addr_mgrp6 *) a, (const net_addr_mgrp6 *) b);
 +  case NET_MPLS:
 +    return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b);
    }
    return 0;
  }
  
 -int
 -net_validate(const net_addr *N)
 +#define NET_HASH(a,t) net_hash_##t((const net_addr_##t *) a)
 +
 +u32
 +net_hash(const net_addr *n)
  {
 -  switch (N->type)
 +  switch (n->type)
    {
 -  case NET_IP4:
 -  case NET_VPN4:
 -  case NET_ROA4:
 -    return net_validate_ip4((net_addr_ip4 *) N);
 +  case NET_IP4: return NET_HASH(n, ip4);
 +  case NET_IP6: return NET_HASH(n, ip6);
 +  case NET_VPN4: return NET_HASH(n, vpn4);
 +  case NET_VPN6: return NET_HASH(n, vpn6);
 +  case NET_ROA4: return NET_HASH(n, roa4);
 +  case NET_ROA6: return NET_HASH(n, roa6);
 +  case NET_FLOW4: return NET_HASH(n, flow4);
 +  case NET_FLOW6: return NET_HASH(n, flow6);
++  case NET_MREQ4: return NET_HASH(n, mreq4);
++  case NET_MREQ6: return NET_HASH(n, mreq6);
++  case NET_MGRP4: return NET_HASH(n, mgrp4);
++  case NET_MGRP6: return NET_HASH(n, mgrp6);
 +  case NET_MPLS: return NET_HASH(n, mpls);
 +  default: bug("invalid type");
 +  }
 +}
  
 -  case NET_IP6:
 -  case NET_VPN6:
 -  case NET_ROA6:
 -    return net_validate_ip6((net_addr_ip6 *) N);
  
 -  case NET_MREQ4:
 -  case NET_MGRP4:
 -    return ip4_classify(((net_addr_mgrp4 *) N)->ga) & IADDR_MULTICAST;
 -  case NET_MREQ6:
 -  case NET_MGRP6:
 -    return ip6_classify(&((net_addr_mgrp6 *) N)->ga) & IADDR_MULTICAST;
 +#define NET_VALIDATE(a,t) net_validate_##t((const net_addr_##t *) a)
  
 -  default:
 -    return 0;
 +int
 +net_validate(const net_addr *n)
 +{
 +  switch (n->type)
 +  {
 +  case NET_IP4: return NET_VALIDATE(n, ip4);
 +  case NET_IP6: return NET_VALIDATE(n, ip6);
 +  case NET_VPN4: return NET_VALIDATE(n, vpn4);
 +  case NET_VPN6: return NET_VALIDATE(n, vpn6);
 +  case NET_ROA4: return NET_VALIDATE(n, roa4);
 +  case NET_ROA6: return NET_VALIDATE(n, roa6);
 +  case NET_FLOW4: return NET_VALIDATE(n, flow4);
 +  case NET_FLOW6: return NET_VALIDATE(n, flow6);
++  case NET_MREQ4: return NET_VALIDATE(n, mreq4);
++  case NET_MREQ6: return NET_VALIDATE(n, mreq6);
++  case NET_MGRP4: return NET_VALIDATE(n, mgrp4);
++  case NET_MGRP6: return NET_VALIDATE(n, mgrp6);
 +  case NET_MPLS: return NET_VALIDATE(n, mpls);
 +  default: return 0;
    }
  }
  
@@@ -219,11 -183,7 +263,15 @@@ net_normalize(net_addr *N
    case NET_IP6:
    case NET_VPN6:
    case NET_ROA6:
 +  case NET_FLOW6:
      return net_normalize_ip6(&n->ip6);
 +
++  case NET_MREQ4:
++  case NET_MREQ6:
++  case NET_MGRP4:
++  case NET_MGRP6:
 +  case NET_MPLS:
 +    return;
    }
  }
  
@@@ -237,17 -197,19 +285,21 @@@ net_classify(const net_addr *N
    case NET_IP4:
    case NET_VPN4:
    case NET_ROA4:
 +  case NET_FLOW4:
++  case NET_MREQ4:
++  case NET_MGRP4:
      return ip4_zero(n->ip4.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip4_classify(n->ip4.prefix);
  
    case NET_IP6:
    case NET_VPN6:
    case NET_ROA6:
 -    return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix);
 -
 -  case NET_MREQ4:
 -  case NET_MGRP4:
 -    return ip4_classify(n->mgrp4.ga);
 +  case NET_FLOW6:
+   case NET_MREQ6:
+   case NET_MGRP6:
 -    return ip6_classify(&n->mgrp6.ga);
 +    return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix);
 +
 +  case NET_MPLS:
 +    return IADDR_HOST | SCOPE_UNIVERSE;
    }
  
    return IADDR_INVALID;
@@@ -274,7 -234,15 +326,17 @@@ ipa_in_netX(const ip_addr a, const net_
      return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)),
                            ip6_mkmask(net6_pxlen(n))));
  
 -    return ip4_equal(ipa_to_ip4(a), ((net_addr_mgrp4 *) n)->ga);
+   case NET_MREQ4:
+   case NET_MGRP4:
+     if (!ipa_is_ip4(a)) return 0;
 -    return ip6_equal(ipa_to_ip6(a), ((net_addr_mgrp6 *) n)->ga);
++    return ip4_equal(ipa_to_ip4(a), net4_prefix(n));
++
+   case NET_MREQ6:
+   case NET_MGRP6:
+     if (ipa_is_ip4(a)) return 0;
++    return ip6_equal(ipa_to_ip6(a), net6_prefix(n));
 +  case NET_MPLS:
    default:
      return 0;
    }
@@@ -288,21 -256,3 +350,25 @@@ net_in_netX(const net_addr *a, const ne
  
    return (net_pxlen(n) <= net_pxlen(a)) && ipa_in_netX(net_prefix(a), n);
  }
 +
 +#define CHECK_NET(T,S) \
 +  ({ if (sizeof(T) != S) die("sizeof %s is %d/%d", #T, (int) sizeof(T), S); })
 +
 +void
 +net_init(void)
 +{
 +  CHECK_NET(net_addr,         24);
 +  CHECK_NET(net_addr_ip4,      8);
 +  CHECK_NET(net_addr_ip6,     20);
 +  CHECK_NET(net_addr_vpn4,    16);
 +  CHECK_NET(net_addr_vpn6,    32);
 +  CHECK_NET(net_addr_roa4,    16);
 +  CHECK_NET(net_addr_roa6,    28);
 +  CHECK_NET(net_addr_flow4,    8);
 +  CHECK_NET(net_addr_flow6,   20);
++  CHECK_NET(net_addr_mreq4,   12);
++  CHECK_NET(net_addr_mreq6,   24);
++  CHECK_NET(net_addr_mgrp4,    8);
++  CHECK_NET(net_addr_mgrp6,   20);
 +  CHECK_NET(net_addr_mpls,     8);
 +}
diff --cc lib/net.h
index 69f006415890c11274fc71d58da757f66eab54fe,6f28f8752465c6408d9843d346fdd504bedf8e2a..de25ad6d29d3cc7845038ef4078b85d62eefc128
+++ b/lib/net.h
  #define NET_VPN6      4
  #define NET_ROA4      5
  #define NET_ROA6      6
 -#define NET_MREQ4     7
 -#define NET_MREQ6     8
 -#define NET_MGRP4     9
 -#define NET_MGRP6     10
 -#define NET_MAX               11
 +#define NET_FLOW4     7
 +#define NET_FLOW6     8
- #define NET_MPLS      9
- #define NET_MAX               10
++#define NET_MREQ4     9
++#define NET_MREQ6     10
++#define NET_MGRP4     11
++#define NET_MGRP6     12
++#define NET_MPLS      13
++#define NET_MAX               14
  
  #define NB_IP4                (1 << NET_IP4)
  #define NB_IP6                (1 << NET_IP6)
  #define NB_VPN6               (1 << NET_VPN6)
  #define NB_ROA4               (1 << NET_ROA4)
  #define NB_ROA6               (1 << NET_ROA6)
 +#define NB_FLOW4      (1 << NET_FLOW4)
 +#define NB_FLOW6      (1 << NET_FLOW6)
+ #define NB_MREQ4      (1 << NET_MREQ4)
+ #define NB_MREQ6      (1 << NET_MREQ6)
+ #define NB_MGRP4      (1 << NET_MGRP4)
+ #define NB_MGRP6      (1 << NET_MGRP6)
 +#define NB_MPLS               (1 << NET_MPLS)
  
  #define NB_IP         (NB_IP4 | NB_IP6)
 -#define NB_MCAST      (NB_MREQ | NB_MGRP)
 -#define NB_6          (NB_IP6 | NB_VPN6 | NB_MREQ6 | NB_MGRP6)
 +#define NB_VPN                (NB_VPN4 | NB_VPN6)
++#define NB_ROA                (NB_ROA4 | NB_ROA6)
 +#define NB_FLOW               (NB_FLOW4 | NB_FLOW6)
+ #define NB_MREQ               (NB_MREQ4 | NB_MREQ6)
+ #define NB_MGRP               (NB_MGRP4 | NB_MGRP6)
++
++#define NB_HOST               (NB_IP | NB_VPN | NB_ROA)
 +#define NB_DEST               (NB_IP | NB_VPN | NB_MPLS)
  #define NB_ANY                0xffffffff
  
  
@@@ -98,29 -100,36 +111,59 @@@ typedef struct net_addr_roa6 
    u32 asn;
  } net_addr_roa6;
  
 -  ip4_addr ga;
 -  unsigned ifindex;
 +typedef struct net_addr_flow4 {
 +  u8 type;
 +  u8 pxlen;
 +  u16 length;
 +  ip4_addr prefix;
 +  byte data[0];
 +} net_addr_flow4;
 +
 +typedef struct net_addr_flow6 {
 +  u8 type;
 +  u8 pxlen;
 +  u16 length;
 +  ip6_addr prefix;
 +  byte data[0];
 +} net_addr_flow6;
 +
+ typedef struct net_addr_mreq4 {
+   u8 type;
+   u8 pxlen;
+   u16 length;
 -  ip6_addr ga;
 -  unsigned ifindex;
++  ip4_addr grp;
++  uint ifindex;
+ } net_addr_mreq4;
+ typedef struct net_addr_mreq6 {
+   u8 type;
+   u8 pxlen;
+   u16 length;
 -  ip4_addr ga;
++  ip6_addr grp;
++  uint ifindex;
+ } net_addr_mreq6;
+ typedef struct net_addr_mgrp4 {
+   u8 type;
+   u8 pxlen;
+   u16 length;
 -  ip6_addr ga;
++  ip4_addr grp;
+ } net_addr_mgrp4;
+ typedef struct net_addr_mgrp6 {
+   u8 type;
+   u8 pxlen;
+   u16 length;
++  ip6_addr grp;
+ } net_addr_mgrp6;
 +typedef struct net_addr_mpls {
 +  u8 type;
 +  u8 pxlen;
 +  u16 length;
 +  u32 label;
 +} net_addr_mpls;
 +
  typedef union net_addr_union {
    net_addr n;
    net_addr_ip4 ip4;
    net_addr_vpn6 vpn6;
    net_addr_roa4 roa4;
    net_addr_roa6 roa6;
 +  net_addr_flow4 flow4;
 +  net_addr_flow6 flow6;
+   net_addr_mreq4 mreq4;
+   net_addr_mreq6 mreq6;
+   net_addr_mgrp4 mgrp4;
+   net_addr_mgrp6 mgrp6;
 +  net_addr_mpls mpls;
  } net_addr_union;
  
  
@@@ -161,14 -171,17 +208,26 @@@ extern const u16 net_max_text_length[]
  #define NET_ADDR_ROA6(prefix,pxlen,max_pxlen,asn) \
    ((net_addr_roa6) { NET_ROA6, pxlen, sizeof(net_addr_roa6), prefix, max_pxlen, asn })
  
 -#define NET_ADDR_MREQ4(ga, ifindex) \
 -  ((net_addr_mreq4) { NET_MREQ4, IP4_MAX_PREFIX_LENGTH, sizeof(net_addr_mreq4), ga, ifindex })
 +#define NET_ADDR_FLOW4(prefix,pxlen,dlen) \
 +  ((net_addr_flow4) { NET_FLOW4, pxlen, sizeof(net_addr_ip4) + dlen, prefix })
 +
 +#define NET_ADDR_FLOW6(prefix,pxlen,dlen) \
 +  ((net_addr_flow6) { NET_FLOW6, pxlen, sizeof(net_addr_ip6) + dlen, prefix })
 +
++#define NET_ADDR_MREQ4(grp, ifindex) \
++  ((net_addr_mreq4) { NET_MREQ4, IP4_MAX_PREFIX_LENGTH, sizeof(net_addr_mreq4), grp, ifindex })
 -#define NET_ADDR_MREQ6(ga, ifindex) \
 -  ((net_addr_mreq6) { NET_MREQ6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mreq6), ga, ifindex })
++#define NET_ADDR_MREQ6(grp, ifindex) \
++  ((net_addr_mreq6) { NET_MREQ6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mreq6), grp, ifindex })
 -#define NET_ADDR_MGRP4(ga) \
 -  ((net_addr_mgrp4) { NET_MGRP4, IP4_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp4), ga })
++#define NET_ADDR_MGRP4(grp) \
++  ((net_addr_mgrp4) { NET_MGRP4, IP4_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp4), grp })
 -#define NET_ADDR_MGRP6(ga) \
 -  ((net_addr_mgrp6) { NET_MGRP6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp6), ga })
++#define NET_ADDR_MGRP6(grp) \
++  ((net_addr_mgrp6) { NET_MGRP6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp6), grp })
++
 +#define NET_ADDR_MPLS(label) \
 +  ((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label })
  
  
  static inline void net_fill_ip4(net_addr *a, ip4_addr prefix, uint pxlen)
@@@ -189,8 -202,17 +248,20 @@@ static inline void net_fill_roa4(net_ad
  static inline void net_fill_roa6(net_addr *a, ip6_addr prefix, uint pxlen, uint max_pxlen, u32 asn)
  { *(net_addr_roa6 *)a = NET_ADDR_ROA6(prefix, pxlen, max_pxlen, asn); }
  
 -static inline void net_fill_mreq4(net_addr *a, ip4_addr ga, unsigned ifindex)
 -{ *(net_addr_mreq4 *)a = NET_ADDR_MREQ4(ga, ifindex); }
++static inline void net_fill_mreq4(net_addr *a, ip4_addr grp, uint ifindex)
++{ *(net_addr_mreq4 *)a = NET_ADDR_MREQ4(grp, ifindex); }
++
++static inline void net_fill_mreq6(net_addr *a, ip6_addr grp, uint ifindex)
++{ *(net_addr_mreq6 *)a = NET_ADDR_MREQ6(grp, ifindex); }
 -static inline void net_fill_mreq6(net_addr *a, ip6_addr ga, unsigned ifindex)
 -{ *(net_addr_mreq6 *)a = NET_ADDR_MREQ6(ga, ifindex); }
++static inline void net_fill_mgrp4(net_addr *a, ip4_addr grp)
++{ *(net_addr_mgrp4 *)a = NET_ADDR_MGRP4(grp); }
 -static inline void net_fill_mgrp4(net_addr *a, ip4_addr ga)
 -{ *(net_addr_mgrp4 *)a = NET_ADDR_MGRP4(ga); }
++static inline void net_fill_mgrp6(net_addr *a, ip6_addr grp)
++{ *(net_addr_mgrp6 *)a = NET_ADDR_MGRP6(grp); }
 -static inline void net_fill_mgrp6(net_addr *a, ip6_addr ga)
 -{ *(net_addr_mgrp6 *)a = NET_ADDR_MGRP6(ga); }
 +static inline void net_fill_mpls(net_addr *a, u32 label)
 +{ *(net_addr_mpls *)a = NET_ADDR_MPLS(label); }
  
  static inline void net_fill_ipa(net_addr *a, ip_addr prefix, uint pxlen)
  {
@@@ -208,18 -230,20 +279,34 @@@ static inline void net_fill_ip_host(net
      net_fill_ip6(a, ipa_to_ip6(prefix), IP6_MAX_PREFIX_LENGTH);
  }
  
 -static inline void net_fill_mreq(net_addr *a, ip_addr ga, unsigned ifindex)
++static inline void net_fill_mreq(net_addr *a, ip_addr grp, unsigned ifindex)
+ {
 -  if (ipa_is_ip4(ga))
 -    net_fill_mreq4(a, ipa_to_ip4(ga), ifindex);
++  if (ipa_is_ip4(grp))
++    net_fill_mreq4(a, ipa_to_ip4(grp), ifindex);
+   else
 -    net_fill_mreq6(a, ipa_to_ip6(ga), ifindex);
++    net_fill_mreq6(a, ipa_to_ip6(grp), ifindex);
+ }
 -static inline void net_fill_mgrp(net_addr *a, ip_addr ga)
++static inline void net_fill_mgrp(net_addr *a, ip_addr grp)
+ {
 -  if (ipa_is_ip4(ga))
 -    net_fill_mgrp4(a, ipa_to_ip4(ga));
++  if (ipa_is_ip4(grp))
++    net_fill_mgrp4(a, ipa_to_ip4(grp));
+   else
 -    net_fill_mgrp6(a, ipa_to_ip6(ga));
++    net_fill_mgrp6(a, ipa_to_ip6(grp));
++}
++
 +static inline void net_fill_flow4(net_addr *a, ip4_addr prefix, uint pxlen, byte *data, uint dlen)
 +{
 +  net_addr_flow4 *f = (void *) a;
 +  *f = NET_ADDR_FLOW4(prefix, pxlen, dlen);
 +  memcpy(f->data, data, dlen);
 +}
 +
 +static inline void net_fill_flow6(net_addr *a, ip6_addr prefix, uint pxlen, byte *data, uint dlen)
 +{
 +  net_addr_flow6 *f = (void *) a;
 +  *f = NET_ADDR_FLOW6(prefix, pxlen, dlen);
 +  memcpy(f->data, data, dlen);
  }
  
  static inline int net_val_match(u8 type, u32 mask)
@@@ -231,15 -255,6 +318,21 @@@ static inline int net_type_match(const 
  static inline int net_is_ip(const net_addr *a)
  { return (a->type == NET_IP4) || (a->type == NET_IP6); }
  
 +static inline int net_is_vpn(const net_addr *a)
 +{ return (a->type == NET_VPN4) || (a->type == NET_VPN6); }
 +
 +static inline int net_is_roa(const net_addr *a)
 +{ return (a->type == NET_ROA4) || (a->type == NET_ROA6); }
 +
 +static inline int net_is_flow(const net_addr *a)
 +{ return (a->type == NET_FLOW4) || (a->type == NET_FLOW6); }
 +
++static inline int net_is_mreq(const net_addr *a)
++{ return (a->type == NET_MREQ4) || (a->type == NET_MREQ6); }
++
++static inline int net_is_mgrp(const net_addr *a)
++{ return (a->type == NET_MGRP4) || (a->type == NET_MGRP6); }
++
  
  static inline ip4_addr net4_prefix(const net_addr *a)
  { return ((net_addr_ip4 *) a)->prefix; }
@@@ -254,16 -269,17 +347,20 @@@ static inline ip_addr net_prefix(const 
    case NET_IP4:
    case NET_VPN4:
    case NET_ROA4:
 +  case NET_FLOW4:
+   case NET_MREQ4:
+   case NET_MGRP4:
      return ipa_from_ip4(net4_prefix(a));
  
    case NET_IP6:
    case NET_VPN6:
    case NET_ROA6:
 +  case NET_FLOW6:
+   case NET_MREQ6:
+   case NET_MGRP6:
      return ipa_from_ip6(net6_prefix(a));
  
 +  case NET_MPLS:
    default:
      return IPA_NONE;
    }
@@@ -292,15 -300,36 +389,29 @@@ static inline u64 net_rd(const net_add
  {
    switch (a->type)
    {
 -  case NET_IP4:
 -  case NET_VPN4: return net4_pxlen(a) == IP4_MAX_PREFIX_LENGTH;
 -  case NET_IP6:
 -  case NET_VPN6: return net6_pxlen(a) == IP6_MAX_PREFIX_LENGTH;
 -  case NET_MREQ4:
 -  case NET_MREQ6:
 -  case NET_MGRP4:
 -  case NET_MGRP6: return 1;
 -  default: return 0;
 +  case NET_VPN4:
-     return ((net_addr_vpn4 *)a)->rd;
++    return ((net_addr_vpn4 *) a)->rd;
 +  case NET_VPN6:
-     return ((net_addr_vpn6 *)a)->rd;
++    return ((net_addr_vpn6 *) a)->rd;
++  default:
++    return 0;
+   }
+ }
 -static inline int net_is_v6(net_addr *a)
 -{
 -  return net_type_match(a, NB_6);
 -}
 -
+ static inline int net_ifindex(net_addr *a)
+ {
+   switch (a->type)
+   {
+   case NET_MREQ4:
 -      return ((net_addr_mreq4 *) a)->ifindex;
++    return ((net_addr_mreq4 *) a)->ifindex;
+   case NET_MREQ6:
 -      return ((net_addr_mreq6 *) a)->ifindex;
 -  default: return 0;
++    return ((net_addr_mreq6 *) a)->ifindex;
++  default:
++    return 0;
    }
-   return 0;
 -
  }
  
 +
  static inline int net_equal(const net_addr *a, const net_addr *b)
  { return (a->length == b->length) && !memcmp(a, b, a->length); }
  
@@@ -357,14 -388,17 +480,26 @@@ static inline int net_zero_roa4(const n
  static inline int net_zero_roa6(const net_addr_roa6 *a)
  { return !a->pxlen && ip6_zero(a->prefix) && !a->max_pxlen && !a->asn; }
  
 -{ return ip4_zero(a->ga) && !a->ifindex; }
 +static inline int net_zero_flow4(const net_addr_flow4 *a)
 +{ return !a->pxlen && ip4_zero(a->prefix) && (a->length == sizeof(net_addr_flow4)); }
 +
 +static inline int net_zero_flow6(const net_addr_flow6 *a)
 +{ return !a->pxlen && ip6_zero(a->prefix) && (a->length == sizeof(net_addr_flow6)); }
 +
+ static inline int net_zero_mreq4(const net_addr_mreq4 *a)
 -{ return ip6_zero(a->ga) && !a->ifindex; }
++{ return ip4_zero(a->grp) && !a->ifindex; }
+ static inline int net_zero_mreq6(const net_addr_mreq6 *a)
 -{ return ip4_zero(a->ga); }
++{ return ip6_zero(a->grp) && !a->ifindex; }
+ static inline int net_zero_mgrp4(const net_addr_mgrp4 *a)
 -{ return ip6_zero(a->ga); }
++{ return ip4_zero(a->grp); }
+ static inline int net_zero_mgrp6(const net_addr_mgrp6 *a)
++{ return ip6_zero(a->grp); }
++
 +static inline int net_zero_mpls(const net_addr_mpls *a)
 +{ return !a->label; }
  
  
  static inline int net_compare_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
@@@ -385,14 -419,17 +520,26 @@@ static inline int net_compare_roa4(cons
  static inline int net_compare_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b)
  { return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->max_pxlen, b->max_pxlen) ?: uint_cmp(a->asn, b->asn); }
  
 -{ return ip4_compare(a->ga, b->ga) ?: uint_cmp(a->ifindex, b->ifindex); }
 +static inline int net_compare_flow4(const net_addr_flow4 *a, const net_addr_flow4 *b)
 +{ return ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->length, b->length) ?: memcmp(a->data, b->data, a->length - sizeof(net_addr_flow4)); }
 +
 +static inline int net_compare_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b)
 +{ return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->length, b->length) ?: memcmp(a->data, b->data, a->length - sizeof(net_addr_flow6)); }
 +
+ static inline int net_compare_mreq4(const net_addr_mreq4 *a, const net_addr_mreq4 *b)
 -{ return ip6_compare(a->ga, b->ga) ?: uint_cmp(a->ifindex, b->ifindex); }
++{ return ip4_compare(a->grp, b->grp) ?: uint_cmp(a->ifindex, b->ifindex); }
+ static inline int net_compare_mreq6(const net_addr_mreq6 *a, const net_addr_mreq6 *b)
 -{ return ip4_compare(a->ga, b->ga); }
++{ return ip6_compare(a->grp, b->grp) ?: uint_cmp(a->ifindex, b->ifindex); }
+ static inline int net_compare_mgrp4(const net_addr_mgrp4 *a, const net_addr_mgrp4 *b)
 -{ return ip6_compare(a->ga, b->ga); }
++{ return ip4_compare(a->grp, b->grp); }
+ static inline int net_compare_mgrp6(const net_addr_mgrp6 *a, const net_addr_mgrp6 *b)
++{ return ip6_compare(a->grp, b->grp); }
++
 +static inline int net_compare_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
 +{ return uint_cmp(a->label, b->label); }
  
  int net_compare(const net_addr *a, const net_addr *b);
  
@@@ -418,15 -455,23 +565,27 @@@ static inline void net_copy_roa4(net_ad
  static inline void net_copy_roa6(net_addr_roa6 *dst, const net_addr_roa6 *src)
  { memcpy(dst, src, sizeof(net_addr_roa6)); }
  
 -static inline u32 net_hash_ip4(const net_addr_ip4 *n)
 -{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
 +static inline void net_copy_flow4(net_addr_flow4 *dst, const net_addr_flow4 *src)
 +{ memcpy(dst, src, src->length); }
 +
 +static inline void net_copy_flow6(net_addr_flow6 *dst, const net_addr_flow6 *src)
 +{ memcpy(dst, src, src->length); }
 +
+ static inline void net_copy_mreq4(net_addr_mreq4 *dst, const net_addr_mreq4 *src)
+ { memcpy(dst, src, sizeof(net_addr_mreq4)); }
+ static inline void net_copy_mreq6(net_addr_mreq6 *dst, const net_addr_mreq6 *src)
+ { memcpy(dst, src, sizeof(net_addr_mreq6)); }
+ static inline void net_copy_mgrp4(net_addr_mgrp4 *dst, const net_addr_mgrp4 *src)
+ { memcpy(dst, src, sizeof(net_addr_mgrp4)); }
+ static inline void net_copy_mgrp6(net_addr_mgrp6 *dst, const net_addr_mgrp6 *src)
+ { memcpy(dst, src, sizeof(net_addr_mgrp6)); }
 +static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
 +{ memcpy(dst, src, sizeof(net_addr_mpls)); }
  
 -static inline u32 net_hash_ip6(const net_addr_ip6 *n)
 -{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
  
  /* XXXX */
  static inline u32 u64_hash(u64 a)
@@@ -450,64 -489,30 +609,88 @@@ static inline u32 net_hash_roa4(const n
  static inline u32 net_hash_roa6(const net_addr_roa6 *n)
  { return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
  
 -{ return ip4_hash(n->ga) ^ u64_hash(n->ifindex); }
 +static inline u32 net_hash_flow4(const net_addr_flow4 *n)
 +{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
 +
 +static inline u32 net_hash_flow6(const net_addr_flow6 *n)
 +{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
 +
+ static inline u32 net_hash_mreq4(const net_addr_mreq4 *n)
 -{ return ip6_hash(n->ga) ^ u64_hash(n->ifindex); }
++{ return ip4_hash(n->grp) ^ u32_hash(n->ifindex); }
+ static inline u32 net_hash_mreq6(const net_addr_mreq6 *n)
 -{ return ip4_hash(n->ga); }
++{ return ip6_hash(n->grp) ^ u32_hash(n->ifindex); }
+ static inline u32 net_hash_mgrp4(const net_addr_mgrp4 *n)
 -{ return ip6_hash(n->ga); }
++{ return ip4_hash(n->grp); }
+ static inline u32 net_hash_mgrp6(const net_addr_mgrp6 *n)
 -static inline int net_validate_ip4(const net_addr_ip4 *n)
++{ return ip6_hash(n->grp); }
 +static inline u32 net_hash_mpls(const net_addr_mpls *n)
 +{ return n->label; }
 +
 +u32 net_hash(const net_addr *a);
 +
 +
 +static inline int net_validate_px4(const ip4_addr prefix, uint pxlen)
  {
 -  return (n->pxlen <= IP4_MAX_PREFIX_LENGTH) &&
 -    ip4_zero(ip4_and(n->prefix, ip4_not(ip4_mkmask(n->pxlen))));
 +  return (pxlen <= IP4_MAX_PREFIX_LENGTH) &&
 +    ip4_zero(ip4_and(prefix, ip4_not(ip4_mkmask(pxlen))));
  }
  
 +static inline int net_validate_px6(const ip6_addr prefix, uint pxlen)
 +{
 +  return (pxlen <= IP6_MAX_PREFIX_LENGTH) &&
 +    ip6_zero(ip6_and(prefix, ip6_not(ip6_mkmask(pxlen))));
 +}
 +
 +static inline int net_validate_ip4(const net_addr_ip4 *n)
 +{ return net_validate_px4(n->prefix, n->pxlen); }
 +
  static inline int net_validate_ip6(const net_addr_ip6 *n)
 +{ return net_validate_px6(n->prefix, n->pxlen); }
 +
 +static inline int net_validate_vpn4(const net_addr_vpn4 *n)
 +{ return net_validate_px4(n->prefix, n->pxlen); }
 +
 +static inline int net_validate_vpn6(const net_addr_vpn6 *n)
 +{ return  net_validate_px6(n->prefix, n->pxlen); }
 +
 +static inline int net_validate_roa4(const net_addr_roa4 *n)
 +{
 +  return net_validate_px4(n->prefix, n->pxlen) &&
 +     (n->pxlen <= n->max_pxlen) && (n->max_pxlen <= IP4_MAX_PREFIX_LENGTH);
 +}
 +
 +static inline int net_validate_roa6(const net_addr_roa6 *n)
  {
 -  return (n->pxlen <= IP6_MAX_PREFIX_LENGTH) &&
 -    ip6_zero(ip6_and(n->prefix, ip6_not(ip6_mkmask(n->pxlen))));
 +  return net_validate_px6(n->prefix, n->pxlen) &&
 +    (n->pxlen <= n->max_pxlen) && (n->max_pxlen <= IP6_MAX_PREFIX_LENGTH);
  }
  
 +// FIXME: Better check, call flow_validate?
 +static inline int net_validate_flow4(const net_addr_flow4 *n)
 +{ return net_validate_px4(n->prefix, n->pxlen); }
 +
 +static inline int net_validate_flow6(const net_addr_flow6 *n)
 +{ return net_validate_px6(n->prefix, n->pxlen); }
 +
++static inline int net_validate_mreq4(const net_addr_mreq4 *n)
++{ return ip4_is_multicast(n->grp); }
++
++static inline int net_validate_mreq6(const net_addr_mreq6 *n)
++{ return ip6_is_multicast(n->grp); }
++
++static inline int net_validate_mgrp4(const net_addr_mgrp4 *n)
++{ return ip4_is_multicast(n->grp); }
++
++static inline int net_validate_mgrp6(const net_addr_mgrp6 *n)
++{ return ip6_is_multicast(n->grp); }
++
 +static inline int net_validate_mpls(const net_addr_mpls *n)
 +{ return n->label < (1 << 20); }
 +
  int net_validate(const net_addr *N);
  
  
diff --cc lib/printf.c
Simple merge
diff --cc lib/socket.h
Simple merge
diff --cc nest/config.Y
index 044aba2b3095bef90832d6094fa71185b68d6385,9bc80054790ae9fe8d2d2f4a7b6f1e92a2769195..6093b586e8e51ed0333dc9666f936fa09e664c70
@@@ -65,24 -64,20 +65,24 @@@ proto_postconfig(void
  CF_DECLS
  
  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(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, MREQ4, MREQ6, MGRP4, MGRP6)
 +CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, TABLE, STATES, ROUTES, FILTERS)
- CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6)
++CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, MREQ4, MREQ6, MGRP4, MGRP6)
  CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
  CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
 -CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE) /* ,ROA */
 -CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
 +CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
 +CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE)
 +CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION, SORTED)
  CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
 +CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
  CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
  
 +/* For r_args_channel */
 +CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
 +
  CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
 -      RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
 +      RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
  CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED)
 -CF_ENUM(T_ENUM_RTC, RTC_, UNICAST, BROADCAST, MULTICAST, ANYCAST)
 -CF_ENUM(T_ENUM_RTD, RTD_, ROUTER, DEVICE, BLACKHOLE, UNREACHABLE, PROHIBIT, MULTIPATH)
 +CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT)
  CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
  
  %type <i32> idval
@@@ -138,13 -148,12 +138,17 @@@ net_type
   | VPN6 { $$ = NET_VPN6; }
   | ROA4 { $$ = NET_ROA4; }
   | ROA6 { $$ = NET_ROA6; }
-  | FLOW4{ $$ = NET_FLOW4; }
-  | FLOW6{ $$ = NET_FLOW6; }
++ | FLOW4 { $$ = NET_FLOW4; }
++ | FLOW6 { $$ = NET_FLOW6; }
+  | MREQ4 { $$ = NET_MREQ4; }
+  | MREQ6 { $$ = NET_MREQ6; }
+  | MGRP4 { $$ = NET_MGRP4; }
+  | MGRP6 { $$ = NET_MGRP6; }
 + | MPLS { $$ = NET_MPLS; }
   ;
  
 +CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6)
 +
  
  /* Creation of routing tables */
  
diff --cc nest/route.h
index 43d7d6968887e0906160a88d0767afc5006622d4,0a3e5cdae5f8c35fcf999f02a402ab7787f79154..7a4b1672fa20de34644992966426c3f85f2c29da
@@@ -247,6 -247,6 +249,9 @@@ typedef struct rte 
        u8 best;                                /* Best route in network, propagated to core */
        u32 metric;                     /* Kernel metric */
      } krt;
++    struct {
++      u32 iifs, oifs;                 /* Bitmaps for iifs and oifs. Use RTE_MGRP_* macros to manipulate. */
++    } mkrt;
    } u;
  } rte;
  
@@@ -275,6 -274,13 +280,13 @@@ static inline int rte_is_filtered(rte *
  #define RIC_REJECT    -1              /* Rejected by protocol */
  #define RIC_DROP      -2              /* Silently dropped by protocol */
  
 -#define RTE_MGRP_SET(iface,m) ((m)|=(1<<if_get_vifi((iface))))
 -#define RTE_MGRP_CLR(iface,m) ((m)&=~(1<<if_get_vifi((iface))))
 -#define RTE_MGRP_ISSET(iface,m)       ((m)&(1<<if_get_vifi((iface))))
 -#define RTE_MGRP_CLRALL(m)    ((m)=0)
 -#define RTE_MGRP_COPY(mfrom,mto)      ((mto)=(mfrom))
 -#define RTE_MGRP_SAME(m1,m2)  ((m1)==(m2))
++#define RTE_MGRP_SET(iface,m) ((m) |= (1 << if_get_vifi((iface))))
++#define RTE_MGRP_CLR(iface,m) ((m) &= ~(1 << if_get_vifi((iface))))
++#define RTE_MGRP_ISSET(iface,m)       ((m) & (1 << if_get_vifi((iface))))
++#define RTE_MGRP_ZERO(m)      ((m) = 0)
++#define RTE_MGRP_COPY(src,dst)        ((dst) = (src))
++#define RTE_MGRP_SAME(m1,m2)  ((m1) == (m2))
  struct config;
  
  void rt_init(void);
@@@ -430,7 -410,10 +442,8 @@@ typedef struct rta 
  #define RTD_BLACKHOLE 2                       /* Silently drop packets */
  #define RTD_UNREACHABLE 3             /* Reject as unreachable */
  #define RTD_PROHIBIT 4                        /* Administratively prohibited */
- #define RTD_MAX 5
 -#define RTD_MULTIPATH 5                       /* Multipath route (nexthops != NULL) */
 -#define RTD_MREQUEST 6                        /* Multicast pseudoroute */
 -#define RTD_MULTICAST 7                       /* Multicast pseudoroute */
 -#define RTD_NONE 8                    /* Invalid RTD */
++#define RTD_MULTICAST 5                       /* Multicast route */
++#define RTD_MAX 6
  
                                        /* Flags for net->n.flags, used by kernel syncer */
  #define KRF_INSTALLED 0x80            /* This route should be installed in the kernel */
diff --cc nest/rt-attr.c
index 761ba9fe8faaa6656323cb50a990c2a9564e72cb,167bfc44a9dd76d5eb64666bd4750b4c8f375eb4..a7b4a74916aa36e8664f52b87dc29ed689269994
  
  #include <stddef.h>
  
 +const char * rta_dest_names[RTD_MAX] = {
 +  [RTD_NONE]          = "",
 +  [RTD_UNICAST]               = "unicast",
 +  [RTD_BLACKHOLE]     = "blackhole",
 +  [RTD_UNREACHABLE]   = "unreachable",
 +  [RTD_PROHIBIT]      = "prohibited",
++  [RTD_MULTICAST]     = "multicast",
 +};
 +
  pool *rta_pool;
  
 -static slab *rta_slab;
 -static slab *mpnh_slab;
 +static slab *rta_slab_[4];
 +static slab *nexthop_slab_[4];
  static slab *rte_src_slab;
  
  static struct idm src_ids;
diff --cc nest/rt-fib.c
index 24a7faccd373634496550691fe32decab9dba42e,cb1f07f4cab151afad76d08763a506070caff6cb..cf755efea74f5bf64f5bb3c13e22f0e3732eabe7
@@@ -211,9 -193,10 +211,13 @@@ fib_hash(struct fib *f, const net_addr 
    case NET_VPN6: return FIB_HASH(f, a, vpn6);
    case NET_ROA4: return FIB_HASH(f, a, roa4);
    case NET_ROA6: return FIB_HASH(f, a, roa6);
 +  case NET_FLOW4: return FIB_HASH(f, a, flow4);
 +  case NET_FLOW6: return FIB_HASH(f, a, flow6);
+   case NET_MREQ4: return FIB_HASH(f, a, mreq4);
+   case NET_MREQ6: return FIB_HASH(f, a, mreq6);
+   case NET_MGRP4: return FIB_HASH(f, a, mgrp4);
+   case NET_MGRP6: return FIB_HASH(f, a, mgrp6);
 +  case NET_MPLS: return FIB_HASH(f, a, mpls);
    default: bug("invalid type");
    }
  }
@@@ -248,9 -231,10 +252,13 @@@ fib_find(struct fib *f, const net_addr 
    case NET_VPN6: return FIB_FIND(f, a, vpn6);
    case NET_ROA4: return FIB_FIND(f, a, roa4);
    case NET_ROA6: return FIB_FIND(f, a, roa6);
 +  case NET_FLOW4: return FIB_FIND(f, a, flow4);
 +  case NET_FLOW6: return FIB_FIND(f, a, flow6);
+   case NET_MREQ4: return FIB_FIND(f, a, mreq4);
+   case NET_MREQ6: return FIB_FIND(f, a, mreq6);
+   case NET_MGRP4: return FIB_FIND(f, a, mgrp4);
+   case NET_MGRP6: return FIB_FIND(f, a, mgrp6);
 +  case NET_MPLS: return FIB_FIND(f, a, mpls);
    default: bug("invalid type");
    }
  }
@@@ -268,9 -252,10 +276,13 @@@ fib_insert(struct fib *f, const net_add
    case NET_VPN6: FIB_INSERT(f, a, e, vpn6); return;
    case NET_ROA4: FIB_INSERT(f, a, e, roa4); return;
    case NET_ROA6: FIB_INSERT(f, a, e, roa6); return;
 +  case NET_FLOW4: FIB_INSERT(f, a, e, flow4); return;
 +  case NET_FLOW6: FIB_INSERT(f, a, e, flow6); return;
+   case NET_MREQ4: FIB_INSERT(f, a, e, mreq4); return;
+   case NET_MREQ6: FIB_INSERT(f, a, e, mreq6); return;
+   case NET_MGRP4: FIB_INSERT(f, a, e, mgrp4); return;
+   case NET_MGRP6: FIB_INSERT(f, a, e, mgrp6); return;
 +  case NET_MPLS: FIB_INSERT(f, a, e, mpls); return;
    default: bug("invalid type");
    }
  }
diff --cc nest/rt-table.c
index b0dd6d3f2d15625bda17a05e234104051dc649af,464107c3fbafd6acb5eb08b1663bb150609aa630..3e15a17d98c7bdc46c396252bf19aeb97b0f9557
@@@ -897,10 -911,10 +897,11 @@@ rte_validate(rte *e
      return 0;
    }
  
 -  mask = net_val_match(n->n.addr->type, NB_MCAST) ? IADDR_MULTICAST : IADDR_HOST;
 -
 -  c = net_classify(n->n.addr);
 -  if ((c < 0) || !(c & mask) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
 +  /* FIXME: better handling different nettypes */
-   c = !net_is_flow(n->n.addr) ?
-     net_classify(n->n.addr): (IADDR_HOST | SCOPE_UNIVERSE);
-   if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
++  /* FIXME: should be check mcast addresses here or in net_validate()? */
++  if (net_type_match(n->n.addr, NB_HOST) &&
++      (c = net_classify(n->n.addr)) &&
++      ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK)))
    {
      log(L_WARN "Ignoring bogus route %N received via %s",
        n->n.addr, e->sender->proto->name);
@@@ -1428,8 -1438,34 +1429,35 @@@ rt_examine(rtable *t, net_addr *a, stru
    rte_update_unlock();
  
    return v > 0;
 -
  }
  
++#if 0
+ /* Sometimes protocols need to find one route in table without keeping their own copy.
+  * rt_route finds the best route after applying filter.
+  * As the routes may be temporary, successful find is announced by the callback.
+  * Returns 1 if the callback was called.
+  */
+ int
+ rt_route(struct channel *c, net_addr *n, void (*callback)(struct proto *, void *, rte *), void *data)
+ {
+   net *r;
+   net_addr *n0 = alloca(n->length);
+   net_copy(n0, n);
+   while (1)
+   {
+     r = net_find(c->table, n0);
+     if (r && rte_is_valid(r->routes) && rt_examine2(r, c->proto, c->out_filter, callback, data))
+       return 1;
+     if (n0->pxlen == 0)
+       return 0;
+     n0->pxlen--;
+     net_normalize(n0);
+   }
+ }
++#endif
  
  /**
   * rt_refresh_begin - start a refresh cycle
@@@ -2358,7 -2321,7 +2386,7 @@@ if_local_addr(ip_addr a, struct iface *
    return 0;
  }
  
- static u32 
 -u32
++static u32
  rt_get_igp_metric(rte *rt)
  {
    eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC);
index b1cc25dce60bb1f5ca09ceb3692ba0e64cd42c74,a90d6ed001dc5833074874c4082e43d72242e533..7b39c0f7cdbd48f98d0250b4cf3808de5bb50e19
@@@ -226,6 -236,25 +226,24 @@@ sk_set_min_ttl6(sock *s, int ttl
    return 0;
  }
  
 -
+ static inline int
+ sk_set_router_alert4(sock *s, int ra)
+ {
+   if (setsockopt(s->fd, SOL_IP, IP_ROUTER_ALERT, &ra, sizeof(ra)) < 0)
+     ERR("IP_ROUTER_ALER");
+   return 0;
+ }
+ static inline int
+ sk_set_router_alert6(sock *s, int ra)
+ {
+   if (setsockopt(s->fd, SOL_IPV6, IPV6_ROUTER_ALERT, &ra, sizeof(ra)) < 0)
+     ERR("IPV6_ROUTER_ALER");
+   return 0;
+ }
  static inline int
  sk_disable_mtu_disc4(sock *s)
  {
Simple merge