]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Core: Prepare for multicast
authorOndřej Hlavatý <aearsis@eideo.cz>
Fri, 27 May 2016 00:40:17 +0000 (02:40 +0200)
committerOndřej Hlavatý <aearsis@eideo.cz>
Fri, 27 May 2016 00:40:17 +0000 (02:40 +0200)
15 files changed:
lib/birdlib.h
lib/hash.h
lib/net.c
lib/net.h
lib/printf.c
lib/socket.h
nest/config.Y
nest/iface.c
nest/iface.h
nest/route.h
nest/rt-fib.c
nest/rt-table.c
sysdep/linux/sysio.h
sysdep/unix/io.c
sysdep/unix/timer.h

index 188e59b2f89f598f46b209026ee3fbacdb5482c4..7b5500b7c6e8593a7f6bea2b3541961a2e5c8ed9 100644 (file)
@@ -64,24 +64,6 @@ static inline int u64_cmp(u64 i1, u64 i2)
 #define PACKED __attribute__((packed))
 
 
-/* Microsecond time */
-
-typedef s64 btime;
-
-#define S_     *1000000
-#define MS_    *1000
-#define US_    *1
-#define TO_S   /1000000
-#define TO_MS  /1000
-#define TO_US  /1
-
-#ifndef PARSER
-#define S      S_
-#define MS     MS_
-#define US     US_
-#endif
-
-
 /* Rate limiting */
 
 struct tbf {
index c2fd8bca5655f6a1c31a030d1967cdca3921cf62..b67efeb242a82c478a12436780370de1566a923e 100644 (file)
@@ -1,4 +1,5 @@
-
+#ifndef BIRD_HASH_H
+#define BIRD_HASH_H
 
 #define HASH(type)             struct { type **data; uint count, order; }
 #define HASH_TYPE(v)           typeof(** (v).data)
@@ -212,3 +213,4 @@ mem_hash(void *p, int s)
   return mem_hash_value(&h);
 }
 
+#endif
index 55eec4b527178d4e8a5cdeef903ba64d613be355..0e7262b2a6599234418d53c4a91cd7b4067192b1 100644 (file)
--- a/lib/net.c
+++ b/lib/net.c
@@ -11,6 +11,10 @@ const char * const net_label[] = {
   [NET_VPN6] = "vpn6",
   [NET_ROA4] = "roa4",
   [NET_ROA6] = "roa6",
+  [NET_MREQ4] = "mreq4",
+  [NET_MREQ6] = "mreq6",
+  [NET_MGRP4] = "mgrp4",
+  [NET_MGRP6] = "mgrp6",
 };
 
 const u16 net_addr_length[] = {
@@ -19,7 +23,11 @@ const u16 net_addr_length[] = {
   [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_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),
 };
 
 const u8 net_max_prefix_length[] = {
@@ -28,7 +36,11 @@ const u8 net_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_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,
 };
 
 const u16 net_max_text_length[] = {
@@ -38,6 +50,10 @@ const u16 net_max_text_length[] = {
   [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" */
 };
 
 
@@ -60,6 +76,12 @@ net_format(const net_addr *N, char *buf, int buflen)
     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_MREQ4:
+  case NET_MGRP4:
+    return bsnprintf(buf, buflen, "%I4", n->mgrp4.ga);
+  case NET_MREQ6:
+  case NET_MGRP6:
+    return bsnprintf(buf, buflen, "%I6", n->mgrp6.ga);
   }
 
   return 0;
@@ -73,11 +95,15 @@ net_pxmask(const net_addr *a)
   case NET_IP4:
   case NET_VPN4:
   case NET_ROA4:
+  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_MREQ6:
+  case NET_MGRP6:
     return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
 
   default:
@@ -105,6 +131,12 @@ net_compare(const net_addr *a, const net_addr *b)
     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_MREQ4:
+  case NET_MGRP4:
+    return net_compare_mgrp4((const net_addr_mgrp4 *) a, (const net_addr_mgrp4 *) b);
+  case NET_MREQ6:
+  case NET_MGRP6:
+    return net_compare_mgrp6((const net_addr_mgrp6 *) a, (const net_addr_mgrp6 *) b);
   }
   return 0;
 }
@@ -124,6 +156,13 @@ net_validate(const net_addr *N)
   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;
+
   default:
     return 0;
   }
@@ -164,6 +203,13 @@ net_classify(const net_addr *N)
   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_MREQ6:
+  case NET_MGRP6:
+    return ip6_classify(&n->mgrp6.ga);
   }
 
   return IADDR_INVALID;
@@ -188,6 +234,15 @@ ipa_in_netX(const ip_addr a, const net_addr *n)
     return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)),
                            ip6_mkmask(net6_pxlen(n))));
 
+  case NET_MREQ4:
+  case NET_MGRP4:
+    if (!ipa_is_ip4(a)) return 0;
+    return ip4_equal(ipa_to_ip4(a), ((net_addr_mgrp4 *) n)->ga);
+  case NET_MREQ6:
+  case NET_MGRP6:
+    if (ipa_is_ip4(a)) return 0;
+    return ip6_equal(ipa_to_ip6(a), ((net_addr_mgrp6 *) n)->ga);
+
   default:
     return 0;
   }
index d9137c4aa50c2ecb8e1a28d39709e5cf70586e76..6f28f8752465c6408d9843d346fdd504bedf8e2a 100644 (file)
--- a/lib/net.h
+++ b/lib/net.h
 #define NET_VPN6       4
 #define NET_ROA4       5
 #define NET_ROA6       6
-#define NET_MAX                7
+#define NET_MREQ4      7
+#define NET_MREQ6      8
+#define NET_MGRP4      9
+#define NET_MGRP6      10
+#define NET_MAX                11
 
 #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_MREQ4       (1 << NET_MREQ4)
+#define NB_MREQ6       (1 << NET_MREQ6)
+#define NB_MGRP4       (1 << NET_MGRP4)
+#define NB_MGRP6       (1 << NET_MGRP6)
 
 #define NB_IP          (NB_IP4 | NB_IP6)
+#define NB_MREQ                (NB_MREQ4 | NB_MREQ6)
+#define NB_MGRP                (NB_MGRP4 | NB_MGRP6)
+#define NB_MCAST       (NB_MREQ | NB_MGRP)
+#define NB_6           (NB_IP6 | NB_VPN6 | NB_MREQ6 | NB_MGRP6)
 #define NB_ANY         0xffffffff
 
 
@@ -88,6 +100,36 @@ typedef struct net_addr_roa6 {
   u32 asn;
 } net_addr_roa6;
 
+typedef struct net_addr_mreq4 {
+  u8 type;
+  u8 pxlen;
+  u16 length;
+  ip4_addr ga;
+  unsigned ifindex;
+} net_addr_mreq4;
+
+typedef struct net_addr_mreq6 {
+  u8 type;
+  u8 pxlen;
+  u16 length;
+  ip6_addr ga;
+  unsigned ifindex;
+} net_addr_mreq6;
+
+typedef struct net_addr_mgrp4 {
+  u8 type;
+  u8 pxlen;
+  u16 length;
+  ip4_addr ga;
+} net_addr_mgrp4;
+
+typedef struct net_addr_mgrp6 {
+  u8 type;
+  u8 pxlen;
+  u16 length;
+  ip6_addr ga;
+} net_addr_mgrp6;
+
 typedef union net_addr_union {
   net_addr n;
   net_addr_ip4 ip4;
@@ -96,6 +138,10 @@ typedef union net_addr_union {
   net_addr_vpn6 vpn6;
   net_addr_roa4 roa4;
   net_addr_roa6 roa6;
+  net_addr_mreq4 mreq4;
+  net_addr_mreq6 mreq6;
+  net_addr_mgrp4 mgrp4;
+  net_addr_mgrp6 mgrp6;
 } net_addr_union;
 
 
@@ -125,6 +171,17 @@ 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_MREQ6(ga, ifindex) \
+  ((net_addr_mreq6) { NET_MREQ6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mreq6), ga, ifindex })
+
+#define NET_ADDR_MGRP4(ga) \
+  ((net_addr_mgrp4) { NET_MGRP4, IP4_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp4), ga })
+
+#define NET_ADDR_MGRP6(ga) \
+  ((net_addr_mgrp6) { NET_MGRP6, IP6_MAX_PREFIX_LENGTH, sizeof(net_addr_mgrp6), ga })
 
 
 static inline void net_fill_ip4(net_addr *a, ip4_addr prefix, uint pxlen)
@@ -145,6 +202,18 @@ static inline void net_fill_roa4(net_addr *a, ip4_addr prefix, uint pxlen, uint
 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_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 ga)
+{ *(net_addr_mgrp4 *)a = NET_ADDR_MGRP4(ga); }
+
+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_ipa(net_addr *a, ip_addr prefix, uint pxlen)
 {
   if (ipa_is_ip4(prefix))
@@ -161,6 +230,21 @@ static inline void net_fill_ip_host(net_addr *a, ip_addr prefix)
     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)
+{
+  if (ipa_is_ip4(ga))
+    net_fill_mreq4(a, ipa_to_ip4(ga), ifindex);
+  else
+    net_fill_mreq6(a, ipa_to_ip6(ga), ifindex);
+}
+
+static inline void net_fill_mgrp(net_addr *a, ip_addr ga)
+{
+  if (ipa_is_ip4(ga))
+    net_fill_mgrp4(a, ipa_to_ip4(ga));
+  else
+    net_fill_mgrp6(a, ipa_to_ip6(ga));
+}
 
 static inline int net_val_match(u8 type, u32 mask)
 { return !!((1 << type) & mask); }
@@ -185,11 +269,15 @@ static inline ip_addr net_prefix(const net_addr *a)
   case NET_IP4:
   case NET_VPN4:
   case NET_ROA4:
+  case NET_MREQ4:
+  case NET_MGRP4:
     return ipa_from_ip4(net4_prefix(a));
 
   case NET_IP6:
   case NET_VPN6:
   case NET_ROA6:
+  case NET_MREQ6:
+  case NET_MGRP6:
     return ipa_from_ip6(net6_prefix(a));
 
   default:
@@ -208,6 +296,39 @@ static inline uint net_pxlen(const net_addr *a)
 
 ip_addr net_pxmask(const net_addr *a);
 
+static inline int net_is_host(const net_addr *a)
+{
+  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;
+  }
+}
+
+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;
+  case NET_MREQ6:
+      return ((net_addr_mreq6 *) a)->ifindex;
+  default: 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); }
@@ -236,6 +357,18 @@ static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_r
 static inline int net_equal_prefix_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b)
 { return ip6_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
 
+static inline int net_equal_mreq4(const net_addr_mreq4 *a, const net_addr_mreq4 *b)
+{ return !memcmp(a, b, sizeof(net_addr_mreq4)); }
+
+static inline int net_equal_mreq6(const net_addr_mreq6 *a, const net_addr_mreq6 *b)
+{ return !memcmp(a, b, sizeof(net_addr_mreq6)); }
+
+static inline int net_equal_mgrp4(const net_addr_mgrp4 *a, const net_addr_mgrp4 *b)
+{ return !memcmp(a, b, sizeof(net_addr_mgrp4)); }
+
+static inline int net_equal_mgrp6(const net_addr_mgrp6 *a, const net_addr_mgrp6 *b)
+{ return !memcmp(a, b, sizeof(net_addr_mgrp6)); }
+
 
 static inline int net_zero_ip4(const net_addr_ip4 *a)
 { return !a->pxlen && ip4_zero(a->prefix); }
@@ -255,6 +388,18 @@ static inline int net_zero_roa4(const net_addr_roa4 *a)
 static inline int net_zero_roa6(const net_addr_roa6 *a)
 { return !a->pxlen && ip6_zero(a->prefix) && !a->max_pxlen && !a->asn; }
 
+static inline int net_zero_mreq4(const net_addr_mreq4 *a)
+{ return ip4_zero(a->ga) && !a->ifindex; }
+
+static inline int net_zero_mreq6(const net_addr_mreq6 *a)
+{ return ip6_zero(a->ga) && !a->ifindex; }
+
+static inline int net_zero_mgrp4(const net_addr_mgrp4 *a)
+{ return ip4_zero(a->ga); }
+
+static inline int net_zero_mgrp6(const net_addr_mgrp6 *a)
+{ return ip6_zero(a->ga); }
+
 
 static inline int net_compare_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
 { return ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); }
@@ -274,6 +419,18 @@ static inline int net_compare_roa4(const net_addr_roa4 *a, const net_addr_roa4 *
 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); }
 
+static inline int net_compare_mreq4(const net_addr_mreq4 *a, const net_addr_mreq4 *b)
+{ return ip4_compare(a->ga, b->ga) ?: uint_cmp(a->ifindex, b->ifindex); }
+
+static inline int net_compare_mreq6(const net_addr_mreq6 *a, const net_addr_mreq6 *b)
+{ return ip6_compare(a->ga, b->ga) ?: uint_cmp(a->ifindex, b->ifindex); }
+
+static inline int net_compare_mgrp4(const net_addr_mgrp4 *a, const net_addr_mgrp4 *b)
+{ return ip4_compare(a->ga, b->ga); }
+
+static inline int net_compare_mgrp6(const net_addr_mgrp6 *a, const net_addr_mgrp6 *b)
+{ return ip6_compare(a->ga, b->ga); }
+
 int net_compare(const net_addr *a, const net_addr *b);
 
 
@@ -298,6 +455,17 @@ static inline void net_copy_roa4(net_addr_roa4 *dst, const net_addr_roa4 *src)
 static inline void net_copy_roa6(net_addr_roa6 *dst, const net_addr_roa6 *src)
 { memcpy(dst, src, sizeof(net_addr_roa6)); }
 
+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 u32 net_hash_ip4(const net_addr_ip4 *n)
 { return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
@@ -321,6 +489,17 @@ static inline u32 net_hash_roa4(const net_addr_roa4 *n)
 static inline u32 net_hash_roa6(const net_addr_roa6 *n)
 { return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
 
+static inline u32 net_hash_mreq4(const net_addr_mreq4 *n)
+{ return ip4_hash(n->ga) ^ u64_hash(n->ifindex); }
+
+static inline u32 net_hash_mreq6(const net_addr_mreq6 *n)
+{ return ip6_hash(n->ga) ^ u64_hash(n->ifindex); }
+
+static inline u32 net_hash_mgrp4(const net_addr_mgrp4 *n)
+{ return ip4_hash(n->ga); }
+
+static inline u32 net_hash_mgrp6(const net_addr_mgrp6 *n)
+{ return ip6_hash(n->ga); }
 
 static inline int net_validate_ip4(const net_addr_ip4 *n)
 {
index 844f596948aeeb02d58a6f8170ac7db9d67a69e4..3c2c245e4ccc87002473904ebfbb290850643349 100644 (file)
@@ -364,6 +364,9 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
                case 'o':
                        base = 8;
                        break;
+               case 'b':
+                       base = 2;
+                       break;
 
                case 'X':
                        flags |= LARGE;
index 7d1aa7efc0070baca2702a8d4fe5ce89d1f454ff..5b8f0dd38c3a1b33ea7e0de8bde126ffce90bb2f 100644 (file)
@@ -77,6 +77,7 @@ static inline int sk_send_buffer_empty(sock *sk)
 int sk_setup_multicast(sock *s);       /* Prepare UDP or IP socket for multicasting */
 int sk_join_group(sock *s, ip_addr maddr);     /* Join multicast group on sk iface */
 int sk_leave_group(sock *s, ip_addr maddr);    /* Leave multicast group on sk iface */
+int sk_set_router_alert(sock *s, int ra);
 int sk_setup_broadcast(sock *s);
 int sk_set_ttl(sock *s, int ttl);      /* Set transmit TTL for given socket */
 int sk_set_min_ttl(sock *s, int ttl);  /* Set minimal accepted TTL for given socket */
index 2961dafb0c466c48e49bdfc18c6f41f70d8702be..9bc80054790ae9fe8d2d2f4a7b6f1e92a2769195 100644 (file)
@@ -65,7 +65,7 @@ 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)
+CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, 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 */
@@ -148,6 +148,10 @@ net_type:
  | VPN6 { $$ = NET_VPN6; }
  | ROA4 { $$ = NET_ROA4; }
  | ROA6 { $$ = NET_ROA6; }
+ | MREQ4 { $$ = NET_MREQ4; }
+ | MREQ6 { $$ = NET_MREQ6; }
+ | MGRP4 { $$ = NET_MGRP4; }
+ | MGRP6 { $$ = NET_MGRP6; }
  ;
 
 
index 00af5052926ff8343cafbaf812224fd6648c073a..d031d4cc9c5ba66747f740a9369fe2905e6521e9 100644 (file)
@@ -502,6 +502,17 @@ ifa_same(struct ifa *a, struct ifa *b)
   return ipa_equal(a->ip, b->ip) && net_equal(&a->prefix, &b->prefix);
 }
 
+struct ifa *
+ifa_find_match(struct iface *i, u32 mask)
+{
+  struct ifa *a;
+
+  WALK_LIST(a, i->addrs)
+    if (net_type_match(&a->prefix, mask))
+      return a;
+
+  return NULL;
+}
 
 /**
  * ifa_update - update interface address
index c4f414ece3a826299ac1e43286910e9c1f21a1e1..a0411f0aace4141966959bcde0d4343aa26fd599 100644 (file)
@@ -88,6 +88,7 @@ void if_show(void);
 void if_show_summary(void);
 struct iface *if_update(struct iface *);
 void if_delete(struct iface *old);
+struct ifa *ifa_find_match(struct iface *i, u32 mask);
 struct ifa *ifa_update(struct ifa *);
 void ifa_delete(struct ifa *);
 void if_start_update(void);
index b5885ee3fb29c7934ae59b38b859095faeeb1542..0a3e5cdae5f8c35fcf999f02a402ab7787f79154 100644 (file)
@@ -200,6 +200,8 @@ struct hostentry {
   u32 igp_metric;                      /* Chosen route IGP metric */
 };
 
+#define RTE_MGRP_MAXVIFS 32
+
 typedef struct rte {
   struct rte *next;
   net *net;                            /* Network this RTE belongs to */
@@ -235,6 +237,9 @@ typedef struct rte {
       u64 router_id;                   /* Babel router id */
     } babel;
 #endif
+    struct {
+       u32 oifs, iifs;                 /* Bitmaps for iifs and oifs. Use RTE_MGRP_* macros to manipulate. */
+    } mkrt;
     struct {                           /* Routes generated by krt sync (both temporary and inherited ones) */
       s8 src;                          /* Alleged route source (see krt.h) */
       u8 proto;                                /* Kernel source protocol ID */
@@ -269,6 +274,13 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
 #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))
+
 struct config;
 
 void rt_init(void);
@@ -287,10 +299,13 @@ void rte_update2(struct channel *c, net_addr *n, rte *new, struct rte_src *src);
 /* rte_update() moved to protocol.h to avoid dependency conflicts */
 void rte_discard(rtable *tab, rte *old);
 int rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter);
+int rt_examine2(net *n, struct proto *p, struct filter *filter, void (*callback)(struct proto *, void *, rte *), void *data);
 rte *rt_export_merged(struct channel *c, net *net, rte **rt_free, struct ea_list **tmpa, int silent);
 void rt_refresh_begin(rtable *t, struct channel *c);
 void rt_refresh_end(rtable *t, struct channel *c);
+int rt_route(struct channel *c, net_addr *net, void (*callback)(struct proto *, void *, rte *), void *data);
 void rt_schedule_prune(rtable *t);
+u32 rt_get_igp_metric(rte *rt);
 void rte_dump(rte *);
 void rte_free(rte *);
 rte *rte_do_cow(rte *);
@@ -396,7 +411,9 @@ typedef struct rta {
 #define RTD_UNREACHABLE 3              /* Reject as unreachable */
 #define RTD_PROHIBIT 4                 /* Administratively prohibited */
 #define RTD_MULTIPATH 5                        /* Multipath route (nexthops != NULL) */
-#define RTD_NONE 6                     /* Invalid RTD */
+#define RTD_MREQUEST 6                 /* Multicast pseudoroute */
+#define RTD_MULTICAST 7                        /* Multicast pseudoroute */
+#define RTD_NONE 8                     /* Invalid RTD */
 
                                        /* Flags for net->n.flags, used by kernel syncer */
 #define KRF_INSTALLED 0x80             /* This route should be installed in the kernel */
index 8021ea24cd314176131697f3e3d6f7f424a70339..cb1f07f4cab151afad76d08763a506070caff6cb 100644 (file)
@@ -193,6 +193,10 @@ fib_hash(struct fib *f, const net_addr *a)
   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_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);
   default: bug("invalid type");
   }
 }
@@ -227,6 +231,10 @@ fib_find(struct fib *f, const net_addr *a)
   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_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);
   default: bug("invalid type");
   }
 }
@@ -244,6 +252,10 @@ fib_insert(struct fib *f, const net_addr *a, struct fib_node *e)
   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_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;
   default: bug("invalid type");
   }
 }
index 9e9d4c7a91b9eb4cb877087f21cb939327bcf1a4..464107c3fbafd6acb5eb08b1663bb150609aa630 100644 (file)
@@ -900,7 +900,7 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
 static inline int
 rte_validate(rte *e)
 {
-  int c;
+  int c, mask;
   net *n = e->net;
 
   // (n->n.pxlen > BITS_PER_IP_ADDRESS) || !ip_is_prefix(n->n.prefix,n->n.pxlen))
@@ -911,8 +911,10 @@ 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 & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
+  if ((c < 0) || !(c & mask) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
   {
     log(L_WARN "Ignoring bogus route %N received via %s",
        n->n.addr, e->sender->proto->name);
@@ -1406,8 +1408,15 @@ int
 rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
 {
   net *n = net_find(t, a);
-  rte *rt = n ? n->routes : NULL;
+  return rt_examine2(n, p, filter, NULL, NULL);
+}
 
+/* If rte would be exported to p, call the callback */
+int
+rt_examine2(net *n, struct proto *p, struct filter *filter, void (*callback)(struct proto *, void *, rte *), void *data)
+{
+  rte *rt = n ? n->routes : NULL;
+  
   if (!rte_is_valid(rt))
     return 0;
 
@@ -1419,6 +1428,9 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
   if (v == RIC_PROCESS)
     v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
 
+  if (callback && v > 0)
+    callback(p, data, rt);
+  
    /* Discard temporary rte */
   if (rt != n->routes)
     rte_free(rt);
@@ -1426,6 +1438,32 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
   rte_update_unlock();
 
   return v > 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);
+  }
 }
 
 
@@ -1734,6 +1772,11 @@ rt_preconfig(struct config *c)
 
   rt_new_table(cf_get_symbol("master4"), NET_IP4);
   rt_new_table(cf_get_symbol("master6"), NET_IP6);
+
+  rt_new_table(cf_get_symbol("mreq4"), NET_MREQ4);
+  rt_new_table(cf_get_symbol("mreq6"), NET_MREQ6);
+  rt_new_table(cf_get_symbol("mroute4"), NET_MGRP4);
+  rt_new_table(cf_get_symbol("mroute6"), NET_MGRP6);
 }
 
 
@@ -2278,7 +2321,7 @@ if_local_addr(ip_addr a, struct iface *i)
   return 0;
 }
 
-static u32 
+u32
 rt_get_igp_metric(rte *rt)
 {
   eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC);
@@ -2439,6 +2482,8 @@ rt_format_via(rte *e, byte *via)
     case RTD_UNREACHABLE:      bsprintf(via, "unreachable"); break;
     case RTD_PROHIBIT: bsprintf(via, "prohibited"); break;
     case RTD_MULTIPATH:        bsprintf(via, "multipath"); break;
+    case RTD_MREQUEST: bsprintf(via, "for %s", a->iface->name); break;
+    case RTD_MULTICAST:        bsprintf(via, "iifs: %b, oifs: %b", e->u.mkrt.iifs, e->u.mkrt.oifs); break;
     default:           bsprintf(via, "???");
     }
 }
index 58644417f9cffda0ea6154f76e0ea94b87f31b4d..a90d6ed001dc5833074874c4082e43d72242e533 100644 (file)
@@ -236,6 +236,25 @@ 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)
 {
index 5ec728af0bf67d98a35cef9a1a7512ca5893ce3a..bd5f3d0644e8bba31894b7fe2152c26cba5170f0 100644 (file)
@@ -122,10 +122,11 @@ tracked_fopen(pool *p, char *name, char *mode)
 #define NEAR_TIMER_LIMIT 4
 
 static list near_timers, far_timers;
-static bird_clock_t first_far_timer = TIME_INFINITY;
+static btime first_far_timer = BTIME_INFINITY;
 
 /* now must be different from 0, because 0 is a special value in timer->expires */
 bird_clock_t now = 1, now_real, boot_time;
+btime now_btime = 1;
 
 static void
 update_times_plain(void)
@@ -134,10 +135,11 @@ update_times_plain(void)
   int delta = new_time - now_real;
 
   if ((delta >= 0) && (delta < 60))
-    now += delta;
+    now_btime += delta S;
   else if (now_real != 0)
    log(L_WARN "Time jump, delta %d s", delta);
 
+  now = now_btime TO_S;
   now_real = new_time;
 }
 
@@ -151,11 +153,14 @@ update_times_gettime(void)
   if (rv != 0)
     die("clock_gettime: %m");
 
-  if (ts.tv_sec != now) {
-    if (ts.tv_sec < now)
+  btime bt = (ts.tv_sec S) + (ts.tv_nsec NS);
+
+  if (bt != now_btime) {
+    if (bt < now_btime)
       log(L_ERR "Monotonic timer is broken");
 
-    now = ts.tv_sec;
+    now_btime = bt;
+    now = now_btime TO_S;
     now_real = time(NULL);
   }
 }
@@ -234,7 +239,7 @@ tm_insert_near(timer *t)
 {
   node *n = HEAD(near_timers);
 
-  while (n->next && (SKIP_BACK(timer, n, n)->expires < t->expires))
+  while (n->next && (SKIP_BACK(timer, n, n)->expires_btime < t->expires_btime))
     n = n->next;
   insert_node(&t->n, n->prev);
 }
@@ -259,17 +264,25 @@ tm_insert_near(timer *t)
 void
 tm_start(timer *t, unsigned after)
 {
-  bird_clock_t when;
-
   if (t->randomize)
     after += random() % (t->randomize + 1);
-  when = now + after;
-  if (t->expires == when)
+
+  tm_start_btime(t, after S);
+}
+
+void
+tm_start_btime(timer *t, btime after)
+{
+  btime when;
+
+  when = now_btime + after;
+  if (t->expires_btime == when)
     return;
-  if (t->expires)
+  if (t->expires_btime)
     rem_node(&t->n);
-  t->expires = when;
-  if (after <= NEAR_TIMER_LIMIT)
+  t->expires_btime = when;
+  t->expires = when TO_S;
+  if (after TO_S <= NEAR_TIMER_LIMIT)
     tm_insert_near(t);
   else
     {
@@ -289,10 +302,10 @@ tm_start(timer *t, unsigned after)
 void
 tm_stop(timer *t)
 {
-  if (t->expires)
+  if (t->expires_btime)
     {
       rem_node(&t->n);
-      t->expires = 0;
+      t->expires = t->expires_btime = 0;
     }
 }
 
@@ -319,16 +332,16 @@ tm_dump_all(void)
   tm_dump_them("Far", &far_timers);
 }
 
-static inline time_t
+static inline btime
 tm_first_shot(void)
 {
-  time_t x = first_far_timer;
+  btime x = first_far_timer;
 
   if (!EMPTY_LIST(near_timers))
     {
       timer *t = SKIP_BACK(timer, n, HEAD(near_timers));
-      if (t->expires < x)
-       x = t->expires;
+      if (t->expires_btime < x)
+       x = t->expires_btime;
     }
   return x;
 }
@@ -341,21 +354,21 @@ tm_shot(void)
   timer *t;
   node *n, *m;
 
-  if (first_far_timer <= now)
+  if (first_far_timer <= now_btime)
     {
-      bird_clock_t limit = now + NEAR_TIMER_LIMIT;
-      first_far_timer = TIME_INFINITY;
+      btime limit = now_btime + NEAR_TIMER_LIMIT S;
+      first_far_timer = BTIME_INFINITY;
       n = HEAD(far_timers);
       while (m = n->next)
        {
          t = SKIP_BACK(timer, n, n);
-         if (t->expires <= limit)
+         if (t->expires_btime <= limit)
            {
              rem_node(n);
              tm_insert_near(t);
            }
-         else if (t->expires < first_far_timer)
-           first_far_timer = t->expires;
+         else if (t->expires_btime < first_far_timer)
+           first_far_timer = t->expires_btime;
          n = m;
        }
     }
@@ -363,17 +376,17 @@ tm_shot(void)
     {
       int delay;
       t = SKIP_BACK(timer, n, n);
-      if (t->expires > now)
+      if (t->expires_btime > now_btime)
        break;
       rem_node(n);
-      delay = t->expires - now;
-      t->expires = 0;
+      delay = t->expires_btime - now_btime;
+      t->expires = t->expires_btime = 0;
       if (t->recurrent)
        {
-         int i = t->recurrent - delay;
+         int i = t->recurrent - delay;
          if (i < 0)
            i = 0;
-         tm_start(t, i);
+         tm_start_btime(t, i);
        }
       io_log_event(t->hook, t->data);
       t->hook(t);
@@ -812,7 +825,7 @@ sk_skip_ip_header(byte *pkt, int *len)
 byte *
 sk_rx_buffer(sock *s, int *len)
 {
-  if (sk_is_ipv4(s) && (s->type == SK_IP))
+  if (sk_is_ipv4(s) && s->type == SK_IP)
     return sk_skip_ip_header(s->rbuf, len);
   else
     return s->rbuf;
@@ -948,6 +961,24 @@ sk_set_min_ttl(sock *s, int ttl)
     return sk_set_min_ttl6(s, ttl);
 }
 
+/**
+ * sk_set_router_alert - set router alert option
+ * @s: socket
+ * @ra: packets with this router alert option value will be passed to the
+ * socket. Negative integer disables.
+ *
+ * Result: 0 for success, -1 for an error.
+ */
+
+int
+sk_set_router_alert(sock *s, int ra)
+{
+  if (sk_is_ipv4(s))
+    return sk_set_router_alert4(s, ra);
+  else
+    return sk_set_router_alert6(s, ra);
+}
+
 #if 0
 /**
  * sk_set_md5_auth - add / remove MD5 security association for given socket
@@ -1087,7 +1118,8 @@ sk_free(resource *r)
       current_sock = sk_next(s);
     if (s == stored_sock)
       stored_sock = sk_next(s);
-    rem_node(&s->n);
+    if (NODE_VALID(&s->n))
+      rem_node(&s->n);
   }
 }
 
@@ -2093,7 +2125,7 @@ void
 io_loop(void)
 {
   int poll_tout;
-  time_t tout;
+  btime tout;
   int nfds, events, pout;
   sock *s;
   node *n;
@@ -2107,12 +2139,12 @@ io_loop(void)
     timers:
       update_times();
       tout = tm_first_shot();
-      if (tout <= now)
+      if (tout <= now_btime)
        {
          tm_shot();
          goto timers;
        }
-      poll_tout = (events ? 0 : MIN(tout - now, 3)) * 1000; /* Time in milliseconds */
+      poll_tout = (events ? 0 : MIN(tout - now_btime, 3)) TO_MS; /* Time in milliseconds */
 
       io_close_event();
 
index 99d43932884b93c242c6df2dceeb6306078e06b6..81da1ef6be9fafe30a99fafdca78ebcbf0f308f1 100644 (file)
 
 #include "lib/resource.h"
 
+/* Microsecond time */
+
+typedef s64 btime;
+
+#define S_     *1000000
+#define MS_    *1000
+#define US_    *1
+#define NS_    /1000
+
+#define TO_S   /1000000
+#define TO_MS  /1000
+#define TO_US  /1
+#define TO_NS  *1000
+
+#ifndef PARSER
+#define S      S_
+#define MS     MS_
+#define US     US_
+#define NS     NS_
+#endif
+
 typedef time_t bird_clock_t;           /* Use instead of time_t */
 
 typedef struct timer {
@@ -22,37 +43,61 @@ typedef struct timer {
   unsigned randomize;                  /* Amount of randomization */
   unsigned recurrent;                  /* Timer recurrence */
   node n;                              /* Internal link */
-  bird_clock_t expires;                        /* 0=inactive */
+  btime expires_btime;                 /* 0=inactive */
+  bird_clock_t expires;                        /* == expires_btime TO_S */
 } timer;
 
 timer *tm_new(pool *);
 void tm_start(timer *, unsigned after);
+void tm_start_btime(timer *, btime after);
 void tm_stop(timer *);
 void tm_dump_all(void);
 
 extern bird_clock_t now;               /* Relative, monotonic time in seconds */
+extern btime now_btime;                        /* dtto in microseconds */
 extern bird_clock_t now_real;          /* Time in seconds since fixed known epoch */
 extern bird_clock_t boot_time;
 
+
 static inline int
 tm_active(timer *t)
 {
-  return t->expires != 0;
+  return t->expires_btime != 0;
+}
+
+static inline btime
+tm_remains_btime(timer *t)
+{
+  return t->expires_btime ? t->expires_btime - now_btime : 0;
 }
 
 static inline bird_clock_t
 tm_remains(timer *t)
 {
-  return t->expires ? t->expires - now : 0;
+  return tm_remains_btime(t) TO_S;
 }
 
 static inline void
-tm_start_max(timer *t, unsigned after)
+tm_start_max_btime(timer *t, btime after)
 {
-  bird_clock_t rem = tm_remains(t);
+  btime rem = tm_remains_btime(t);
   tm_start(t, (rem > after) ? rem : after);
 }
 
+static inline void
+tm_start_min_btime(timer *t, btime after)
+{
+  btime rem = tm_remains_btime(t);
+  if (!rem || after < rem)
+    tm_start(t, after);
+}
+
+static inline void
+tm_start_max(timer *t, unsigned after)
+{
+  tm_start_max_btime(t, after S_);
+}
+
 static inline timer *
 tm_new_set(pool *p, void (*hook)(struct timer *), void *data, unsigned rand, unsigned rec)
 {
@@ -87,4 +132,6 @@ tm_format_datetime(char *x, struct timeformat *fmt_spec, bird_clock_t t);
 #endif
 #endif
 
+#define BTIME_INFINITY 0x7fffffffffffffff
+
 #endif