--- /dev/null
- - ./configure --enable-ipv6=$IPV6 CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS"
+ variables:
+ DEBIAN_FRONTEND: noninteractive
+ LC_ALL: C
+ GIT_STRATEGY: fetch
+ DOCKER_CMD: docker --config="$HOME/.docker/$CI_JOB_ID/"
+ IMG_BASE: registry.labs.nic.cz/labs/bird
+
+ stages:
+ - image
+ - build
+
+ .docker: &docker_build
+ stage: image
+ allow_failure: true
+ script:
+ - $DOCKER_CMD login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.labs.nic.cz
+ # Make sure we refresh the base image if it updates (eg. security updates, etc)
+ # If we do just the build, cache is always reused and the freshness of the
+ # base image is never checked. However, pull always asks and updates the
+ # image only if it changed ‒ therefore, the cache is used unless there's a
+ # change.
+ - $DOCKER_CMD pull `sed -ne 's/^FROM //p' "misc/docker/$IMG_NAME/Dockerfile"`
+ - $DOCKER_CMD build -t "bird:$IMG_NAME" "misc/docker/$IMG_NAME"
+ - $DOCKER_CMD tag "bird:$IMG_NAME" "$IMG_BASE:$IMG_NAME"
+ - $DOCKER_CMD push "$IMG_BASE:$IMG_NAME"
+ after_script:
+ - rm -f "$HOME/.docker/$CI_JOB_ID/" # cleanup the credentials
+ tags:
+ # That's Docker in Docker
+ - dind
+
+ docker_debian-7-amd64:
+ variables:
+ IMG_NAME: "debian-7-amd64"
+ <<: *docker_build
+
+ docker_debian-8-amd64:
+ variables:
+ IMG_NAME: "debian-8-amd64"
+ <<: *docker_build
+
+ docker_debian-9-amd64:
+ variables:
+ IMG_NAME: "debian-9-amd64"
+ <<: *docker_build
+
+ docker_debian-testing-amd64:
+ variables:
+ IMG_NAME: "debian-testing-amd64"
+ <<: *docker_build
+
+ docker_debian-7-i386:
+ variables:
+ IMG_NAME: "debian-7-i386"
+ <<: *docker_build
+
+ docker_debian-8-i386:
+ variables:
+ IMG_NAME: "debian-8-i386"
+ <<: *docker_build
+
+ docker_debian-9-i386:
+ variables:
+ IMG_NAME: "debian-9-i386"
+ <<: *docker_build
+
+ docker_debian-testing-i386:
+ variables:
+ IMG_NAME: "debian-testing-i386"
+ <<: *docker_build
+
+ docker_fedora-25-amd64:
+ variables:
+ IMG_NAME: "fedora-25-amd64"
+ <<: *docker_build
+
+ docker_fedora-26-amd64:
+ variables:
+ IMG_NAME: "fedora-26-amd64"
+ <<: *docker_build
+
+ docker_centos-6-amd64:
+ variables:
+ IMG_NAME: "centos-6-amd64"
+ <<: *docker_build
+
+ docker_centos-7-amd64:
+ variables:
+ IMG_NAME: "centos-7-amd64"
+ <<: *docker_build
+
+ docker_opensuse-42_3-amd64:
+ variables:
+ IMG_NAME: "opensuse-42.3-amd64"
+ <<: *docker_build
+
+ docker_ubuntu-14_04-amd64:
+ variables:
+ IMG_NAME: "ubuntu-14.04-amd64"
+ <<: *docker_build
+
+ docker_ubuntu-16_04-amd64:
+ variables:
+ IMG_NAME: "ubuntu-16.04-amd64"
+ <<: *docker_build
+
+ .debian-7-i386: &debian-7-i386_env
+ image: registry.labs.nic.cz/labs/bird:debian-7-i386
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .debian-8-i386: &debian-8-i386_env
+ image: registry.labs.nic.cz/labs/bird:debian-8-i386
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .debian-9-i386: &debian-9-i386_env
+ image: registry.labs.nic.cz/labs/bird:debian-9-i386
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .debian-testing-i386: &debian-testing-i386_env
+ image: registry.labs.nic.cz/labs/bird:debian-testing-i386
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .debian-7-amd64: &debian-7-amd64_env
+ image: registry.labs.nic.cz/labs/bird:debian-7-amd64
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .debian-8-amd64: &debian-8-amd64_env
+ image: registry.labs.nic.cz/labs/bird:debian-8-amd64
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .debian-9-amd64: &debian-9-amd64_env
+ image: registry.labs.nic.cz/labs/bird:debian-9-amd64
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .debian-testing-amd64: &debian-testing-amd64_env
+ image: registry.labs.nic.cz/labs/bird:debian-testing-amd64
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .fedora-25-amd64: &fedora-25-amd64_env
+ image: registry.labs.nic.cz/labs/bird:fedora-25-amd64
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .fedora-26-amd64: &fedora-26-amd64_env
+ image: registry.labs.nic.cz/labs/bird:fedora-26-amd64
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .centos-6-amd64: ¢os-6-amd64_env
+ image: registry.labs.nic.cz/labs/bird:centos-6-amd64
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .centos-7-amd64: ¢os-7-amd64_env
+ image: registry.labs.nic.cz/labs/bird:centos-7-amd64
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .opensuse-42_3-amd64: &opensuse-42_3-amd64_env
+ image: registry.labs.nic.cz/labs/bird:opensuse-42.3-amd64
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .ubuntu-14_04-amd64: &ubuntu-14_04-amd64_env
+ image: registry.labs.nic.cz/labs/bird:ubuntu-14.04-amd64
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ .ubuntu-16_04-amd64: &ubuntu-16_04-amd64_env
+ image: registry.labs.nic.cz/labs/bird:ubuntu-16.04-amd64
+ tags:
+ - docker
+ - linux
+ - amd64
+
+ # TODO We want to copy these BSDs to our own virtual machines, to make sure someone doesn't update them by accident.
+ .freebsd-11-i386: &freebsd-11-i386_env
+ variables:
+ CPPFLAGS: "-I/usr/local/include"
+ LDFLAGS: "-L/usr/local/lib"
+ tags:
+ - freebsd
+ - i386
+ #only:
+ #- master
+ #- triggers
+ #- tags
+
+ .freebsd-11-amd64: &freebsd-11-amd64_env
+ variables:
+ CPPFLAGS: "-I/usr/local/include"
+ LDFLAGS: "-L/usr/local/lib"
+ tags:
+ - freebsd
+ - amd64
+ #only:
+ #- master
+ #- triggers
+ #- tags
+
+ .build: &build_job
+ stage: build
+ script:
+ - autoreconf
-build-debian-7-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *debian-7-amd64_env
- <<: *build_job
-
-build-debian-8-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *debian-8-amd64_env
- <<: *build_job
-
-build-debian-9-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *debian-9-amd64_env
- <<: *build_job
-
-build-debian-testing-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *debian-testing-amd64_env
- <<: *build_job
-
++ - ./configure CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS"
+ # Detect which make is available
+ - MAKE=make
+ - which gmake 2>/dev/null >/dev/null && MAKE=gmake
+ - $MAKE
+ # Run tests if they are available (eg. don't fail if "check" isn't a valid make target)
+ - $MAKE check || [ "$?" = 2 ]
+
+ build-debian-7-amd64:
+ variables:
+ IPV6: "no"
+ <<: *debian-7-amd64_env
+ <<: *build_job
+
+ build-debian-8-amd64:
+ variables:
+ IPV6: "no"
+ <<: *debian-8-amd64_env
+ <<: *build_job
+
+ build-debian-9-amd64:
+ variables:
+ IPV6: "no"
+ <<: *debian-9-amd64_env
+ <<: *build_job
+
+ build-debian-testing-amd64:
+ variables:
+ IPV6: "no"
+ <<: *debian-testing-amd64_env
+ <<: *build_job
+
-build-fedora-25-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *fedora-25-amd64_env
- <<: *build_job
-
+ build-fedora-25-amd64:
+ variables:
+ IPV6: "no"
+ <<: *fedora-25-amd64_env
+ <<: *build_job
+
-build-fedora-26-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *fedora-26-amd64_env
- <<: *build_job
-
+ build-fedora-26-amd64:
+ variables:
+ IPV6: "no"
+ <<: *fedora-26-amd64_env
+ <<: *build_job
+
-build-centos-6-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *centos-6-amd64_env
- <<: *build_job
-
+ build-centos-6-amd64:
+ variables:
+ IPV6: "no"
+ <<: *centos-6-amd64_env
+ <<: *build_job
+
-build-centos-7-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *centos-7-amd64_env
- <<: *build_job
-
+ build-centos-7-amd64:
+ variables:
+ IPV6: "no"
+ <<: *centos-7-amd64_env
+ <<: *build_job
+
-build-opensuse-42_3-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *opensuse-42_3-amd64_env
- <<: *build_job
-
+ build-opensuse-42_3-amd64:
+ variables:
+ IPV6: "no"
+ <<: *opensuse-42_3-amd64_env
+ <<: *build_job
+
-build-ubuntu-14_04-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *ubuntu-14_04-amd64_env
- <<: *build_job
-
+ build-ubuntu-14_04-amd64:
+ variables:
+ IPV6: "no"
+ <<: *ubuntu-14_04-amd64_env
+ <<: *build_job
+
-build-ubuntu-16_04-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *ubuntu-16_04-amd64_env
- <<: *build_job
-
+ build-ubuntu-16_04-amd64:
+ variables:
+ IPV6: "no"
+ <<: *ubuntu-16_04-amd64_env
+ <<: *build_job
+
-build-debian-7-i386-v6:
- variables:
- IPV6: "yes"
- <<: *debian-7-i386_env
- <<: *build_job
-
+ build-debian-7-i386:
+ variables:
+ IPV6: "no"
+ <<: *debian-7-i386_env
+ <<: *build_job
+
-build-debian-8-i386-v6:
- variables:
- IPV6: "yes"
- <<: *debian-8-i386_env
- <<: *build_job
-
+ build-debian-8-i386:
+ variables:
+ IPV6: "no"
+ <<: *debian-8-i386_env
+ <<: *build_job
+
-build-debian-9-i386-v6:
- variables:
- IPV6: "yes"
- <<: *debian-9-i386_env
- <<: *build_job
-
+ build-debian-9-i386:
+ variables:
+ IPV6: "no"
+ <<: *debian-9-i386_env
+ <<: *build_job
+
-build-debian-testing-i386-v6:
- variables:
- IPV6: "yes"
- <<: *debian-testing-i386_env
- <<: *build_job
-
+ build-debian-testing-i386:
+ variables:
+ IPV6: "no"
+ <<: *debian-testing-i386_env
+ <<: *build_job
+
-build-freebsd-11-amd64-v6:
- variables:
- IPV6: "yes"
- <<: *freebsd-11-amd64_env
- <<: *build_job
-
+ build-freebsd-11-amd64:
+ variables:
+ IPV6: "no"
+ <<: *freebsd-11-amd64_env
+ <<: *build_job
+
-
-build-freebsd-i386-v6:
- variables:
- IPV6: "yes"
- <<: *freebsd-11-i386_env
- <<: *build_job
+ build-freebsd-11-i386:
+ variables:
+ IPV6: "no"
+ <<: *freebsd-11-i386_env
+ <<: *build_job
--- /dev/null
+/*
+ * BIRD Internet Routing Daemon -- Network addresses
+ *
+ * (c) 2015 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2015 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_NET_H_
+#define _BIRD_NET_H_
+
+#include "lib/ip.h"
+
+
+#define NET_IP4 1
+#define NET_IP6 2
+#define NET_VPN4 3
+#define NET_VPN6 4
+#define NET_ROA4 5
+#define NET_ROA6 6
+#define NET_FLOW4 7
+#define NET_FLOW6 8
+#define NET_MPLS 9
+#define NET_MAX 10
+
+#define NB_IP4 (1 << NET_IP4)
+#define NB_IP6 (1 << NET_IP6)
+#define NB_VPN4 (1 << NET_VPN4)
+#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_MPLS (1 << NET_MPLS)
+
+#define NB_IP (NB_IP4 | NB_IP6)
+#define NB_VPN (NB_VPN4 | NB_VPN6)
+#define NB_FLOW (NB_FLOW4 | NB_FLOW6)
+#define NB_DEST (NB_IP | NB_VPN | NB_MPLS)
+#define NB_ANY 0xffffffff
+
+
+typedef struct net_addr {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ u8 data[16];
+ u64 align[0];
+} net_addr;
+
+typedef struct net_addr_ip4 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip4_addr prefix;
+} net_addr_ip4;
+
+typedef struct net_addr_ip6 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip6_addr prefix;
+} net_addr_ip6;
+
+typedef struct net_addr_vpn4 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip4_addr prefix;
+ u64 rd;
+} net_addr_vpn4;
+
+typedef struct net_addr_vpn6 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip6_addr prefix;
+ u64 rd;
+} net_addr_vpn6;
+
+typedef struct net_addr_roa4 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip4_addr prefix;
+ u32 max_pxlen;
+ u32 asn;
+} net_addr_roa4;
+
+typedef struct net_addr_roa6 {
+ u8 type;
+ u8 pxlen;
+ u16 length;
+ ip6_addr prefix;
+ u32 max_pxlen;
+ u32 asn;
+} net_addr_roa6;
+
+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_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_ip6 ip6;
+ net_addr_vpn4 vpn4;
+ net_addr_vpn6 vpn6;
+ net_addr_roa4 roa4;
+ net_addr_roa6 roa6;
+ net_addr_flow4 flow4;
+ net_addr_flow6 flow6;
+ net_addr_mpls mpls;
+} net_addr_union;
+
+
+extern const char * const net_label[];
+extern const u16 net_addr_length[];
+extern const u8 net_max_prefix_length[];
+extern const u16 net_max_text_length[];
+
+#define NET_MAX_TEXT_LENGTH 256
+
+
+#define NET_ADDR_IP4(prefix,pxlen) \
+ ((net_addr_ip4) { NET_IP4, pxlen, sizeof(net_addr_ip4), prefix })
+
+#define NET_ADDR_IP6(prefix,pxlen) \
+ ((net_addr_ip6) { NET_IP6, pxlen, sizeof(net_addr_ip6), prefix })
+
+#define NET_ADDR_VPN4(prefix,pxlen,rd) \
+ ((net_addr_vpn4) { NET_VPN4, pxlen, sizeof(net_addr_vpn4), prefix, rd })
+
+#define NET_ADDR_VPN6(prefix,pxlen,rd) \
+ ((net_addr_vpn6) { NET_VPN6, pxlen, sizeof(net_addr_vpn6), prefix, rd })
+
+#define NET_ADDR_ROA4(prefix,pxlen,max_pxlen,asn) \
+ ((net_addr_roa4) { NET_ROA4, pxlen, sizeof(net_addr_roa4), prefix, max_pxlen, asn })
+
+#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_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_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)
+{ *(net_addr_ip4 *)a = NET_ADDR_IP4(prefix, pxlen); }
+
+static inline void net_fill_ip6(net_addr *a, ip6_addr prefix, uint pxlen)
+{ *(net_addr_ip6 *)a = NET_ADDR_IP6(prefix, pxlen); }
+
+static inline void net_fill_vpn4(net_addr *a, ip4_addr prefix, uint pxlen, u64 rd)
+{ *(net_addr_vpn4 *)a = NET_ADDR_VPN4(prefix, pxlen, rd); }
+
+static inline void net_fill_vpn6(net_addr *a, ip6_addr prefix, uint pxlen, u64 rd)
+{ *(net_addr_vpn6 *)a = NET_ADDR_VPN6(prefix, pxlen, rd); }
+
+static inline void net_fill_roa4(net_addr *a, ip4_addr prefix, uint pxlen, uint max_pxlen, u32 asn)
+{ *(net_addr_roa4 *)a = NET_ADDR_ROA4(prefix, pxlen, max_pxlen, asn); }
+
+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_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)
+{
+ if (ipa_is_ip4(prefix))
+ net_fill_ip4(a, ipa_to_ip4(prefix), pxlen);
+ else
+ net_fill_ip6(a, ipa_to_ip6(prefix), pxlen);
+}
+
+static inline void net_fill_ip_host(net_addr *a, ip_addr prefix)
+{
+ if (ipa_is_ip4(prefix))
+ net_fill_ip4(a, ipa_to_ip4(prefix), IP4_MAX_PREFIX_LENGTH);
+ else
+ net_fill_ip6(a, ipa_to_ip6(prefix), IP6_MAX_PREFIX_LENGTH);
+}
+
+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)
+{ return !!((1 << type) & mask); }
+
+static inline int net_type_match(const net_addr *a, u32 mask)
+{ return net_val_match(a->type, mask); }
+
+static inline int net_is_ip(const net_addr *a)
+{ return (a->type == NET_IP4) || (a->type == NET_IP6); }
+
+static inline int net_is_roa(const net_addr *a)
+{ return (a->type == NET_ROA4) || (a->type == NET_ROA6); }
+
+static inline int net_is_vpn(const net_addr *a)
+{ return (a->type == NET_VPN4) || (a->type == NET_VPN6); }
+
+
+static inline ip4_addr net4_prefix(const net_addr *a)
+{ return ((net_addr_ip4 *) a)->prefix; }
+
+static inline ip6_addr net6_prefix(const net_addr *a)
+{ return ((net_addr_ip6 *) a)->prefix; }
+
+static inline ip_addr net_prefix(const net_addr *a)
+{
+ switch (a->type)
+ {
+ case NET_IP4:
+ case NET_VPN4:
+ case NET_ROA4:
+ case NET_FLOW4:
+ return ipa_from_ip4(net4_prefix(a));
+
+ case NET_IP6:
+ case NET_VPN6:
+ case NET_ROA6:
+ case NET_FLOW6:
+ return ipa_from_ip6(net6_prefix(a));
+
+ case NET_MPLS:
+ default:
+ return IPA_NONE;
+ }
+}
+
+static inline u32 net_mpls(const net_addr *a)
+{
+ if (a->type == NET_MPLS)
+ return ((net_addr_mpls *) a)->label;
+
+ bug("Can't call net_mpls on non-mpls net_addr");
+}
+
+static inline uint net4_pxlen(const net_addr *a)
+{ return a->pxlen; }
+
+static inline uint net6_pxlen(const net_addr *a)
+{ return a->pxlen; }
+
+static inline uint net_pxlen(const net_addr *a)
+{ return a->pxlen; }
+
+ip_addr net_pxmask(const net_addr *a);
+
+static inline u64 net_rd(const net_addr *a)
+{
+ switch (a->type)
+ {
+ case NET_VPN4:
+ return ((net_addr_vpn4 *)a)->rd;
+ case NET_VPN6:
+ return ((net_addr_vpn6 *)a)->rd;
+ }
+ 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); }
+
+static inline int net_equal_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
+{ return !memcmp(a, b, sizeof(net_addr_ip4)); }
+
+static inline int net_equal_ip6(const net_addr_ip6 *a, const net_addr_ip6 *b)
+{ return !memcmp(a, b, sizeof(net_addr_ip6)); }
+
+static inline int net_equal_vpn4(const net_addr_vpn4 *a, const net_addr_vpn4 *b)
+{ return !memcmp(a, b, sizeof(net_addr_vpn4)); }
+
+static inline int net_equal_vpn6(const net_addr_vpn6 *a, const net_addr_vpn6 *b)
+{ return !memcmp(a, b, sizeof(net_addr_vpn6)); }
+
+static inline int net_equal_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b)
+{ return !memcmp(a, b, sizeof(net_addr_roa4)); }
+
+static inline int net_equal_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b)
+{ return !memcmp(a, b, sizeof(net_addr_roa6)); }
+
+static inline int net_equal_flow4(const net_addr_flow4 *a, const net_addr_flow4 *b)
+{ return net_equal((const net_addr *) a, (const net_addr *) b); }
+
+static inline int net_equal_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b)
+{ return net_equal((const net_addr *) a, (const net_addr *) b); }
+
+static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
+{ return !memcmp(a, b, sizeof(net_addr_mpls)); }
+
+
+static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b)
+{ return ip4_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
+
+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_zero_ip4(const net_addr_ip4 *a)
+{ return !a->pxlen && ip4_zero(a->prefix); }
+
+static inline int net_zero_ip6(const net_addr_ip6 *a)
+{ return !a->pxlen && ip6_zero(a->prefix); }
+
+static inline int net_zero_vpn4(const net_addr_vpn4 *a)
+{ return !a->pxlen && ip4_zero(a->prefix) && !a->rd; }
+
+static inline int net_zero_vpn6(const net_addr_vpn6 *a)
+{ return !a->pxlen && ip6_zero(a->prefix) && !a->rd; }
+
+static inline int net_zero_roa4(const net_addr_roa4 *a)
+{ return !a->pxlen && ip4_zero(a->prefix) && !a->max_pxlen && !a->asn; }
+
+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_flow4(const net_addr_flow4 *a)
+{ return !a->pxlen && ip4_zero(a->prefix) && !a->data; }
+
+static inline int net_zero_flow6(const net_addr_flow6 *a)
+{ return !a->pxlen && ip6_zero(a->prefix) && !a->data; }
+
+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)
+{ return ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); }
+
+static inline int net_compare_ip6(const net_addr_ip6 *a, const net_addr_ip6 *b)
+{ return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); }
+
+static inline int net_compare_vpn4(const net_addr_vpn4 *a, const net_addr_vpn4 *b)
+{ return u64_cmp(a->rd, b->rd) ?: ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); }
+
+static inline int net_compare_vpn6(const net_addr_vpn6 *a, const net_addr_vpn6 *b)
+{ return u64_cmp(a->rd, b->rd) ?: ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); }
+
+static inline int net_compare_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b)
+{ return ip4_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_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_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_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);
+
+
+static inline void net_copy(net_addr *dst, const net_addr *src)
+{ memcpy(dst, src, src->length); }
+
+static inline void net_copy_ip4(net_addr_ip4 *dst, const net_addr_ip4 *src)
+{ memcpy(dst, src, sizeof(net_addr_ip4)); }
+
+static inline void net_copy_ip6(net_addr_ip6 *dst, const net_addr_ip6 *src)
+{ memcpy(dst, src, sizeof(net_addr_ip6)); }
+
+static inline void net_copy_vpn4(net_addr_vpn4 *dst, const net_addr_vpn4 *src)
+{ memcpy(dst, src, sizeof(net_addr_vpn4)); }
+
+static inline void net_copy_vpn6(net_addr_vpn6 *dst, const net_addr_vpn6 *src)
+{ memcpy(dst, src, sizeof(net_addr_vpn6)); }
+
+static inline void net_copy_roa4(net_addr_roa4 *dst, const net_addr_roa4 *src)
+{ memcpy(dst, src, sizeof(net_addr_roa4)); }
+
+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_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_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
+{ memcpy(dst, src, sizeof(net_addr_mpls)); }
+
+
+/* XXXX */
+static inline u32 u64_hash(u64 a)
+{ return u32_hash(a); }
+
+static inline u32 net_hash_ip4(const net_addr_ip4 *n)
+{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
+
+static inline u32 net_hash_ip6(const net_addr_ip6 *n)
+{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
+
+static inline u32 net_hash_vpn4(const net_addr_vpn4 *n)
+{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); }
+
+static inline u32 net_hash_vpn6(const net_addr_vpn6 *n)
+{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); }
+
+static inline u32 net_hash_roa4(const net_addr_roa4 *n)
+{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
+
+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_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_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 (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 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_mpls(const net_addr_mpls *n)
+{ return n->label < (1 << 20); }
+
+int net_validate(const net_addr *N);
+
+
+static inline void net_normalize_ip4(net_addr_ip4 *n)
+{ n->prefix = ip4_and(n->prefix, ip4_mkmask(n->pxlen)); }
+
+static inline void net_normalize_ip6(net_addr_ip6 *n)
+{ n->prefix = ip6_and(n->prefix, ip6_mkmask(n->pxlen)); }
+
+static inline void net_normalize_vpn4(net_addr_vpn4 *n)
+{ net_normalize_ip4((net_addr_ip4 *) n); }
+
+static inline void net_normalize_vpn6(net_addr_vpn6 *n)
+{ net_normalize_ip6((net_addr_ip6 *) n); }
+
+void net_normalize(net_addr *N);
+
+
+int net_classify(const net_addr *N);
+int net_format(const net_addr *N, char *buf, int buflen);
+int rd_format(const u64 rd, char *buf, int buflen);
+
++static inline int ipa_in_net_ip4(ip4_addr a, const net_addr_ip4 *n)
++{ return ip4_zero(ip4_and(ip4_xor(a, n->prefix), ip4_mkmask(n->pxlen))); }
++
++static inline int net_in_net_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
++{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip4(a->prefix, b); }
++
++static inline int ipa_in_net_ip6(ip6_addr a, const net_addr_ip6 *n)
++{ return ip6_zero(ip6_and(ip6_xor(a, n->prefix), ip6_mkmask(n->pxlen))); }
++
++static inline int net_in_net_ip6(const net_addr_ip6 *a, const net_addr_ip6 *b)
++{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip6(a->prefix, b); }
++
+int ipa_in_netX(const ip_addr A, const net_addr *N);
+int net_in_netX(const net_addr *A, const net_addr *N);
+
+
+#endif
static inline void
ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
{
- if (p->ifa_notify)
+ if (p->ifa_notify && (p->proto_state != PS_DOWN))
{
if (p->debug & D_IFACES)
- log(L_TRACE "%s < %s address %N on interface %s %s",
- p->name, (a->flags & IA_PRIMARY) ? "primary" : "secondary",
- &a->prefix, a->iface->name, (c & IF_CHANGE_UP) ? "added" : "removed");
- log(L_TRACE "%s <%s address %I/%d on interface %s %s",
- p->name, (a->flags & IA_PRIMARY) ? " primary" : "",
- a->prefix, a->pxlen, a->iface->name,
++ log(L_TRACE "%s < address %N on interface %s %s",
++ p->name, &a->prefix, a->iface->name,
+ (c & IF_CHANGE_UP) ? "added" : "removed");
p->ifa_notify(p, c, a);
}
}
| MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error("Min delay must be positive"); }
| MANAGED bool { RADV_IFACE->managed = $2; }
| OTHER CONFIG bool { RADV_IFACE->other_config = $3; }
- | LINK MTU expr { RADV_IFACE->link_mtu = $3; if ($3 < 0) cf_error("Link MTU must be 0 or positive"); }
- | REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if (($3 < 0) || ($3 > 3600000)) cf_error("Reachable time must be in range 0-3600000"); }
- | RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; if ($3 < 0) cf_error("Retrans timer must be 0 or positive"); }
- | LINGER TIME expr { RADV_IFACE->linger_time = $3; if (($3 < 0) || ($3 > 3600)) cf_error("Linger time must be in range 0-3600"); }
- | CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if (($4 < 0) || ($4 > 255)) cf_error("Current hop limit must be in range 0-255"); }
+ | LINK MTU expr { RADV_IFACE->link_mtu = $3; }
+ | REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if ($3 > 3600000) cf_error("Reachable time must be in range 0-3600000"); }
+ | RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; }
++ | LINGER TIME expr { RADV_IFACE->linger_time = $3; if ($3 > 3600) cf_error("Linger time must be in range 0-3600"); }
+ | CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if ($4 > 255) cf_error("Current hop limit must be in range 0-255"); }
| DEFAULT LIFETIME expr radv_sensitive {
RADV_IFACE->default_lifetime = $3;
- if (($3 < 0) || ($3 > 9000)) cf_error("Default lifetime must be in range 0-9000");
- if ($4 != -1) RADV_IFACE->default_lifetime_sensitive = $4;
+ if ($3 > 9000) cf_error("Default lifetime must be in range 0-9000");
+ if ($4 != (uint) -1) RADV_IFACE->default_lifetime_sensitive = $4;
}
| DEFAULT PREFERENCE radv_preference { RADV_IFACE->default_preference = $3; }
| PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
return -1;
}
-radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *prefix,
+ static int
- struct radv_prefix_config *pc = prefix->cf;
++radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *px,
+ char **buf, char *bufend)
+ {
- op->pxlen = prefix->len;
++ struct radv_prefix_config *pc = px->cf;
+
+ if (*buf + sizeof(struct radv_opt_prefix) > bufend)
+ {
+ log(L_WARN "%s: Too many prefixes on interface %s",
+ ifa->ra->p.name, ifa->iface->name);
+ return -1;
+ }
+
+ struct radv_opt_prefix *op = (void *) *buf;
+ op->type = OPT_PREFIX;
+ op->length = 4;
- op->prefix = prefix->prefix;
- ipa_hton(op->prefix);
++ op->pxlen = px->prefix.pxlen;
+ op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) |
+ (pc->autonomous ? OPT_PX_AUTONOMOUS : 0);
+ op->valid_lifetime = (ifa->ra->active || !pc->valid_lifetime_sensitive) ?
+ htonl(pc->valid_lifetime) : 0;
+ op->preferred_lifetime = (ifa->ra->active || !pc->preferred_lifetime_sensitive) ?
+ htonl(pc->preferred_lifetime) : 0;
+ op->reserved = 0;
++ op->prefix = ip6_hton(px->prefix.prefix);
+ *buf += sizeof(*op);
+
+ return 0;
+ }
+
static void
radv_prepare_ra(struct radv_iface *ifa)
{
int
radv_sk_open(struct radv_iface *ifa)
{
- sock *sk = sk_new(ifa->ra->p.pool);
+ sock *sk = sk_new(ifa->pool);
sk->type = SK_IP;
+ sk->subtype = SK_IPV6;
sk->dport = ICMPV6_PROTO;
sk->saddr = ifa->addr->ip;
RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
- if (ifa->prefix_expires && (ifa->prefix_expires <= now))
+ /*
+ * If some dead prefixes expired, regenerate the prefix list and the packet.
+ * We do so by pretending there was a change on the interface.
+ *
+ * This sets the timer, but we replace it just at the end of this function
+ * (replacing a timer is fine).
+ */
++ if (ifa->prefix_expires && (ifa->prefix_expires <= current_time()))
+ radv_iface_notify(ifa, RA_EV_GC);
+
radv_send_ra(ifa, 0);
/* Update timer */
- ifa->last = now;
- unsigned after = ifa->cf->min_ra_int;
- after += random() % (ifa->cf->max_ra_int - ifa->cf->min_ra_int + 1);
+ ifa->last = current_time();
+ btime t = ifa->cf->min_ra_int S;
+ btime r = (ifa->cf->max_ra_int - ifa->cf->min_ra_int) S;
+ t += random() % (r + 1);
if (ifa->initial)
+ {
+ t = MIN(t, MAX_INITIAL_RTR_ADVERT_INTERVAL);
ifa->initial--;
+ }
- if (ifa->initial)
- after = MIN(after, MAX_INITIAL_RTR_ADVERT_INTERVAL);
-
- tm_start(ifa->timer, after);
+ tm_start(ifa->timer, t);
}
- static char* ev_name[] = { NULL, "Init", "Change", "RS" };
+ static struct radv_prefix_config default_prefix = {
+ .onlink = 1,
+ .autonomous = 1,
+ .valid_lifetime = DEFAULT_VALID_LIFETIME,
+ .preferred_lifetime = DEFAULT_PREFERRED_LIFETIME
+ };
+
+ static struct radv_prefix_config dead_prefix = {
+ };
+
+ /* Find a corresponding config for the given prefix */
+ static struct radv_prefix_config *
-radv_prefix_match(struct radv_iface *ifa, struct ifa *a)
++radv_prefix_match(struct radv_iface *ifa, net_addr_ip6 *px)
+ {
+ struct radv_proto *p = ifa->ra;
+ struct radv_config *cf = (struct radv_config *) (p->p.cf);
+ struct radv_prefix_config *pc;
+
- if (a->scope <= SCOPE_LINK)
- return NULL;
-
+ WALK_LIST(pc, ifa->cf->pref_list)
- if ((a->pxlen >= pc->pxlen) && ipa_in_net(a->prefix, pc->prefix, pc->pxlen))
++ if (net_in_net_ip6(px, &pc->prefix))
+ return pc;
+
+ WALK_LIST(pc, cf->pref_list)
- if ((a->pxlen >= pc->pxlen) && ipa_in_net(a->prefix, pc->prefix, pc->pxlen))
++ if (net_in_net_ip6(px, &pc->prefix))
+ return pc;
+
+ return &default_prefix;
+ }
+
+ /*
+ * Go through the list of prefixes, compare them with configs and decide if we
+ * want them or not.
+ */
+ static void
+ radv_prepare_prefixes(struct radv_iface *ifa)
+ {
+ struct radv_proto *p = ifa->ra;
+ struct radv_iface_config *cf = ifa->cf;
+ struct radv_prefix *pfx;
+
+ /* First mark all the prefixes as unused */
+ WALK_LIST(pfx, ifa->prefixes)
+ pfx->mark = 0;
+
+ /* Find all the prefixes we want to use and make sure they are in the list. */
+ struct ifa *addr;
+ WALK_LIST(addr, ifa->iface->addrs)
+ {
- struct radv_prefix_config *pc = radv_prefix_match(ifa, addr);
++ if ((addr->prefix.type != NET_IP6) ||
++ (addr->scope <= SCOPE_LINK))
++ continue;
++
++ net_addr_ip6 *prefix = (void *) &addr->prefix;
++ struct radv_prefix_config *pc = radv_prefix_match(ifa, prefix);
+
+ if (!pc || pc->skip)
+ continue;
+
+ /* Do we have it already? */
+ struct radv_prefix *existing = NULL;
+ WALK_LIST(pfx, ifa->prefixes)
- if ((pfx->len == addr->pxlen) && ipa_equal(pfx->prefix, addr->prefix))
++ if (net_equal_ip6(&pfx->prefix, prefix))
+ {
+ existing = pfx;
+ break;
+ }
+
+ if (!existing)
+ {
- RADV_TRACE(D_EVENTS, "Adding new prefix %I/%d on %s",
- addr->prefix, addr->pxlen, ifa->iface->name);
++ RADV_TRACE(D_EVENTS, "Adding new prefix %N on %s",
++ prefix, ifa->iface->name);
+
+ existing = mb_allocz(ifa->pool, sizeof *existing);
- existing->prefix = addr->prefix;
- existing->len = addr->pxlen;
++ net_copy_ip6(&existing->prefix, prefix);
+ add_tail(&ifa->prefixes, NODE existing);
+ }
+
+ /*
+ * Update the information (it may have changed, or even bring a prefix back
+ * to life).
+ */
+ existing->alive = 1;
+ existing->mark = 1;
+ existing->cf = pc;
+ }
+
+ /*
+ * Garbage-collect the prefixes. If something isn't used, it dies (but isn't
+ * dropped just yet). If something is dead and rots there for long enough,
+ * clean it up.
+ */
- bird_clock_t expires = now + cf->linger_time;
- bird_clock_t expires_min = 0;
++ btime now_ = current_time();
++ btime expires = now_ + cf->linger_time S;
++ btime expires_min = 0;
+ struct radv_prefix *next;
+ WALK_LIST_DELSAFE(pfx, next, ifa->prefixes)
+ {
+ if (pfx->alive && !pfx->mark)
+ {
- RADV_TRACE(D_EVENTS, "Marking prefix %I/$d on %s as dead",
- pfx->prefix, pfx->len, ifa->iface->name);
++ RADV_TRACE(D_EVENTS, "Marking prefix %N on %s as dead",
++ pfx->prefix, ifa->iface->name);
+
+ pfx->alive = 0;
+ pfx->expires = expires;
+ pfx->cf = &dead_prefix;
+ }
+
+ if (!pfx->alive)
+ {
- if (pfx->expires <= now)
++ if (pfx->expires <= now_)
+ {
- RADV_TRACE(D_EVENTS, "Removing prefix %I/%d on %s",
- pfx->prefix, pfx->len, ifa->iface->name);
++ RADV_TRACE(D_EVENTS, "Removing prefix %N on %s",
++ pfx->prefix, ifa->iface->name);
+
+ rem_node(NODE pfx);
+ mb_free(pfx);
+ }
+ else
+ {
+ /* Find minimum expiration time */
+ if (!expires_min || (pfx->expires < expires_min))
+ expires_min = pfx->expires;
+ }
+ }
+ }
+
+ ifa->prefix_expires = expires_min;
+ }
+
+ static char* ev_name[] = { NULL, "Init", "Change", "RS", "Garbage collect" };
void
radv_iface_notify(struct radv_iface *ifa, int event)
break;
}
+ radv_prepare_prefixes(ifa);
+
/* Update timer */
- unsigned delta = now - ifa->last;
- unsigned after = 0;
-
- if (delta < ifa->cf->min_delay)
- after = ifa->cf->min_delay - delta;
-
- tm_start(ifa->timer, after);
+ btime t = ifa->last + ifa->cf->min_delay S - current_time();
+ tm_start(ifa->timer, t);
}
static void
ifa->ra = p;
ifa->cf = cf;
ifa->iface = iface;
+ ifa->addr = iface->llv6;
+ init_list(&ifa->prefixes);
add_tail(&p->iface_list, NODE ifa);
u8 active; /* Whether radv is active w.r.t. triggers */
};
- ip_addr prefix;
- u8 len;
+ struct radv_prefix /* One prefix we advertise */
+ {
+ node n;
- bird_clock_t expires; /* The time when we drop this prefix from
++ net_addr_ip6 prefix;
++
+ u8 alive; /* Is the prefix alive? If not, we advertise it
+ with 0 lifetime, so clients stop using it */
+ u8 mark; /* A temporary mark for processing */
++ btime expires; /* The time when we drop this prefix from
+ advertising. It is valid only if !alive. */
+ struct radv_prefix_config *cf; /* The config tied to this prefix */
+ };
+
struct radv_iface
{
node n;
struct radv_iface_config *cf; /* Related config, must be updated in reconfigure */
struct iface *iface;
struct ifa *addr; /* Link-local address of iface */
- bird_clock_t prefix_expires; /* When the soonest prefix expires (0 = none dead) */
+ struct pool *pool; /* A pool for interface-specific things */
+ list prefixes; /* The prefixes we advertise (struct radv_prefix) */
++ btime prefix_expires; /* When the soonest prefix expires (0 = none dead) */
timer *timer;
struct object_lock *lock;
sock *sk;
- bird_clock_t last; /* Time of last sending of RA */
+ btime last; /* Time of last sending of RA */
u16 plen; /* Length of prepared RA in tbuf, or 0 if not valid */
- byte initial; /* List of active ifaces */
+ byte initial; /* How many RAs are still to be sent as initial */
};
#define RA_EV_INIT 1 /* Switch to initial mode */
[IFA_LOCAL] = { 1, 1, sizeof(ip6_addr) },
[IFA_FLAGS] = { 1, 1, sizeof(u32) },
};
-#endif
-#define BIRD_RTA_MAX (RTA_TABLE+1)
+#define BIRD_RTA_MAX (RTA_ENCAP+1)
-#ifndef IPV6
-static struct nl_want_attrs mpnh_attr_want4[BIRD_RTA_MAX] = {
+static struct nl_want_attrs nexthop_attr_want4[BIRD_RTA_MAX] = {
[RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) },
+ [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
+ [RTA_ENCAP] = { 1, 0, 0 },
};
-#else
-static struct nl_want_attrs mpnh_attr_want6[BIRD_RTA_MAX] = {
+
++static struct nl_want_attrs nexthop_attr_want6[BIRD_RTA_MAX] = {
+ [RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) },
++ [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
++ [RTA_ENCAP] = { 1, 0, 0 },
++};
++
+static struct nl_want_attrs encap_mpls_want[BIRD_RTA_MAX] = {
+ [RTA_DST] = { 1, 0, 0 },
};
-#endif
-#ifndef IPV6
static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
[RTA_DST] = { 1, 1, sizeof(ip4_addr) },
[RTA_OIF] = { 1, 1, sizeof(u32) },
[RTA_PRIORITY] = { 1, 1, sizeof(u32) },
[RTA_PREFSRC] = { 1, 1, sizeof(ip6_addr) },
[RTA_METRICS] = { 1, 0, 0 },
+ [RTA_MULTIPATH] = { 1, 0, 0 },
[RTA_FLOW] = { 1, 1, sizeof(u32) },
[RTA_TABLE] = { 1, 1, sizeof(u32) },
+ [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
+ [RTA_ENCAP] = { 1, 0, 0 },
+};
+
+static struct nl_want_attrs rtm_attr_want_mpls[BIRD_RTA_MAX] = {
+ [RTA_DST] = { 1, 1, sizeof(u32) },
+ [RTA_IIF] = { 1, 1, sizeof(u32) },
+ [RTA_OIF] = { 1, 1, sizeof(u32) },
+ [RTA_PRIORITY] = { 1, 1, sizeof(u32) },
+ [RTA_METRICS] = { 1, 0, 0 },
+ [RTA_FLOW] = { 1, 1, sizeof(u32) },
+ [RTA_TABLE] = { 1, 1, sizeof(u32) },
+ [RTA_VIA] = { 1, 0, 0 },
+ [RTA_NEWDST] = { 1, 0, 0 },
};
-#endif
static int
nl_close_attr(h, a);
}
-static struct mpnh *
+static struct nexthop *
- nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
+ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra, int af)
{
/* Temporary buffer for multicast nexthops */
- static struct mpnh *nh_buffer;
+ static struct nexthop *nh_buffer;
static int nh_buf_size; /* in number of structures */
static int nh_buf_used;
/* Nonexistent RTNH_PAYLOAD ?? */
nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0);
- nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want4, a, sizeof(a));
+ switch (af)
+ {
-#ifndef IPV6
+ case AF_INET:
- if (!nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want4, a, sizeof(a)))
++ if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want4, a, sizeof(a)))
+ return NULL;
+ break;
-#else
++
+ case AF_INET6:
- if (!nl_parse_attrs(RTNH_DATA(nh), mpnh_attr_want6, a, sizeof(a)))
++ if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want6, a, sizeof(a)))
+ return NULL;
+ break;
-#endif
++
+ default:
+ return NULL;
+ }
+
if (a[RTA_GATEWAY])
{
- memcpy(&rv->gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(rv->gw));
- ipa_ntoh(rv->gw);
+ rv->gw = rta_get_ipa(a[RTA_GATEWAY]);
+
+ if (nh->rtnh_flags & RTNH_F_ONLINK)
+ rv->flags |= RNF_ONLINK;
- neighbor *ng = neigh_find2(&p->p, &rv->gw, rv->iface,
- (nh->rtnh_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0);
- if (!ng || (ng->scope == SCOPE_HOST))
+ neighbor *nbr;
+ nbr = neigh_find2(&p->p, &rv->gw, rv->iface,
+ (rv->flags & RNF_ONLINK) ? NEF_ONLINK : 0);
+ if (!nbr || (nbr->scope == SCOPE_HOST))
return NULL;
}
else
switch (i->rtm_type)
{
case RTN_UNICAST:
+ ra->dest = RTD_UNICAST;
- if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET))
- {
- struct nexthop *nh = nl_parse_multipath(p, a[RTA_MULTIPATH]);
+ if (a[RTA_MULTIPATH])
- {
- ra->dest = RTD_MULTIPATH;
- ra->nexthops = nl_parse_multipath(p, a[RTA_MULTIPATH], i->rtm_family);
- if (!ra->nexthops)
++ {
++ struct nexthop *nh = nl_parse_multipath(p, a[RTA_MULTIPATH], i->rtm_family);
+ if (!nh)
{
- log(L_ERR "KRT: Received strange multipath route %I/%d",
- net->n.prefix, net->n.pxlen);
+ log(L_ERR "KRT: Received strange multipath route %N", net->n.addr);
return;
}