From: Ondrej Zajicek (work) Date: Thu, 7 Dec 2017 16:41:09 +0000 (+0100) Subject: Merge commit '98bb80a243b58c43453e9be69d19d0350286549c' into int-new X-Git-Tag: v2.0.0~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4ff15a75c56531fa2d3858d8250dcef1af4e75b6;p=thirdparty%2Fbird.git Merge commit '98bb80a243b58c43453e9be69d19d0350286549c' into int-new --- 4ff15a75c56531fa2d3858d8250dcef1af4e75b6 diff --cc .gitlab-ci.yml index 000000000,c9863a1c2..059894841 mode 000000,100644..100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@@ -1,0 -1,451 +1,349 @@@ + 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 - - ./configure --enable-ipv6=$IPV6 CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS" ++ - ./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-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 - + build-fedora-25-amd64: + variables: + IPV6: "no" + <<: *fedora-25-amd64_env + <<: *build_job + -build-fedora-25-amd64-v6: - variables: - IPV6: "yes" - <<: *fedora-25-amd64_env - <<: *build_job - + build-fedora-26-amd64: + variables: + IPV6: "no" + <<: *fedora-26-amd64_env + <<: *build_job + -build-fedora-26-amd64-v6: - variables: - IPV6: "yes" - <<: *fedora-26-amd64_env - <<: *build_job - + build-centos-6-amd64: + variables: + IPV6: "no" + <<: *centos-6-amd64_env + <<: *build_job + -build-centos-6-amd64-v6: - variables: - IPV6: "yes" - <<: *centos-6-amd64_env - <<: *build_job - + build-centos-7-amd64: + variables: + IPV6: "no" + <<: *centos-7-amd64_env + <<: *build_job + -build-centos-7-amd64-v6: - variables: - IPV6: "yes" - <<: *centos-7-amd64_env - <<: *build_job - + build-opensuse-42_3-amd64: + variables: + IPV6: "no" + <<: *opensuse-42_3-amd64_env + <<: *build_job + -build-opensuse-42_3-amd64-v6: - variables: - IPV6: "yes" - <<: *opensuse-42_3-amd64_env - <<: *build_job - + build-ubuntu-14_04-amd64: + variables: + IPV6: "no" + <<: *ubuntu-14_04-amd64_env + <<: *build_job + -build-ubuntu-14_04-amd64-v6: - variables: - IPV6: "yes" - <<: *ubuntu-14_04-amd64_env - <<: *build_job - + build-ubuntu-16_04-amd64: + variables: + IPV6: "no" + <<: *ubuntu-16_04-amd64_env + <<: *build_job + -build-ubuntu-16_04-amd64-v6: - variables: - IPV6: "yes" - <<: *ubuntu-16_04-amd64_env - <<: *build_job - + build-debian-7-i386: + variables: + IPV6: "no" + <<: *debian-7-i386_env + <<: *build_job + -build-debian-7-i386-v6: - variables: - IPV6: "yes" - <<: *debian-7-i386_env - <<: *build_job - + build-debian-8-i386: + variables: + IPV6: "no" + <<: *debian-8-i386_env + <<: *build_job + -build-debian-8-i386-v6: - variables: - IPV6: "yes" - <<: *debian-8-i386_env - <<: *build_job - + build-debian-9-i386: + variables: + IPV6: "no" + <<: *debian-9-i386_env + <<: *build_job + -build-debian-9-i386-v6: - variables: - IPV6: "yes" - <<: *debian-9-i386_env - <<: *build_job - + build-debian-testing-i386: + variables: + IPV6: "no" + <<: *debian-testing-i386_env + <<: *build_job + -build-debian-testing-i386-v6: - variables: - IPV6: "yes" - <<: *debian-testing-i386_env - <<: *build_job - + build-freebsd-11-amd64: + variables: + IPV6: "no" + <<: *freebsd-11-amd64_env + <<: *build_job + -build-freebsd-11-amd64-v6: - variables: - IPV6: "yes" - <<: *freebsd-11-amd64_env - <<: *build_job - + build-freebsd-11-i386: + variables: + IPV6: "no" + <<: *freebsd-11-i386_env + <<: *build_job - -build-freebsd-i386-v6: - variables: - IPV6: "yes" - <<: *freebsd-11-i386_env - <<: *build_job diff --cc lib/net.h index 332f4c9a8,000000000..cae3a7498 mode 100644,000000..100644 --- a/lib/net.h +++ b/lib/net.h @@@ -1,533 -1,0 +1,545 @@@ +/* + * BIRD Internet Routing Daemon -- Network addresses + * + * (c) 2015 Ondrej Zajicek + * (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 diff --cc nest/iface.c index 01b1aa481,ff362938e..dbc4debe4 --- a/nest/iface.c +++ b/nest/iface.c @@@ -142,12 -138,13 +142,12 @@@ if_copy(struct iface *to, struct iface 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); } } diff --cc proto/radv/config.Y index b5f4b5f24,0ff84aeb5..0e43c237c --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@@ -91,14 -94,15 +92,15 @@@ radv_iface_item | 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); } diff --cc proto/radv/packets.c index 9ea8feee2,19d71f977..e07296e10 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@@ -234,6 -205,37 +204,36 @@@ radv_prepare_dnssl(struct radv_iface *i return -1; } + static int -radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *prefix, ++radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *px, + char **buf, char *bufend) + { - struct radv_prefix_config *pc = prefix->cf; ++ 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->pxlen = prefix->len; ++ 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 = prefix->prefix; - ipa_hton(op->prefix); ++ op->prefix = ip6_hton(px->prefix.prefix); + *buf += sizeof(*op); + + return 0; + } + static void radv_prepare_ra(struct radv_iface *ifa) { @@@ -408,9 -384,8 +382,9 @@@ radv_err_hook(sock *sk, int err 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; diff --cc proto/radv/radv.c index fe371ab40,227c8ef62..c96d77248 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@@ -51,24 -51,160 +51,163 @@@ radv_timer(timer *tm RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name); + /* + * 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 <= now)) ++ 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) @@@ -92,9 -229,16 +232,11 @@@ 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 @@@ -146,7 -302,7 +289,8 @@@ radv_iface_new(struct radv_proto *p, st ifa->ra = p; ifa->cf = cf; ifa->iface = iface; + ifa->addr = iface->llv6; + init_list(&ifa->prefixes); add_tail(&p->iface_list, NODE ifa); diff --cc proto/radv/radv.h index 8324bb67a,60b9980f1..4672e3b2e --- a/proto/radv/radv.h +++ b/proto/radv/radv.h @@@ -118,6 -125,19 +122,19 @@@ struct radv_prot u8 active; /* Whether radv is active w.r.t. triggers */ }; + struct radv_prefix /* One prefix we advertise */ + { + node n; - ip_addr prefix; - u8 len; ++ 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 */ - bird_clock_t expires; /* The time when we drop this prefix from ++ 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; @@@ -125,14 -145,17 +142,17 @@@ struct radv_iface_config *cf; /* Related config, must be updated in reconfigure */ struct iface *iface; struct ifa *addr; /* Link-local address of iface */ + struct pool *pool; /* A pool for interface-specific things */ + list prefixes; /* The prefixes we advertise (struct radv_prefix) */ - bird_clock_t prefix_expires; /* When the soonest prefix expires (0 = none dead) */ ++ 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 */ diff --cc sysdep/linux/netlink.c index 6cea2fa99,3658c46ba..279f3c9c8 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@@ -338,20 -319,22 +342,26 @@@ static struct nl_want_attrs ifa_attr_wa [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) }, @@@ -374,23 -355,11 +384,24 @@@ static struct nl_want_attrs rtm_attr_wa [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 @@@ -630,11 -487,11 +641,11 @@@ nl_add_multipath(struct nlmsghdr *h, ui 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; @@@ -670,18 -526,31 +681,33 @@@ /* 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 @@@ -1518,14 -1266,15 +1544,14 @@@ nl_parse_route(struct nl_parse_state *s 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; }