diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2017-12-07 13:06:01 +0100 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2017-12-07 13:06:01 +0100 |
commit | 153f02da3bce1f3f1a99295648679c71327e8319 (patch) | |
tree | b7b7acf8026ba182f3a81f2d6da975b0b1524972 /sysdep | |
parent | 4ae3ee1200b386219673c2168eae996c6207b077 (diff) |
Nest: Maintain separate IPv4, IPv6 and LLv6 preferred addresses
Also redesign preferred address selection and update protocols to use
appropriate preferred address.
Based on a previous work by Jan Maria Matejka.
Diffstat (limited to 'sysdep')
-rw-r--r-- | sysdep/bsd/krt-sock.c | 41 | ||||
-rw-r--r-- | sysdep/bsd/sysio.h | 4 | ||||
-rw-r--r-- | sysdep/linux/netlink.c | 6 | ||||
-rw-r--r-- | sysdep/unix/krt.Y | 44 | ||||
-rw-r--r-- | sysdep/unix/krt.c | 74 | ||||
-rw-r--r-- | sysdep/unix/krt.h | 20 | ||||
-rw-r--r-- | sysdep/unix/unix.h | 3 |
7 files changed, 93 insertions, 99 deletions
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index df639816..be8b50d6 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -287,18 +287,21 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) #endif { /* Fallback for all other valid cases */ - if (!i->addr) - { - log(L_ERR "KRT: interface %s has no IP addess", i->name); - return -1; - } #ifdef RTF_CLONING if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */ msg.rtm.rtm_flags |= RTF_CLONING; #endif - sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0); + struct ifa *addr = (net->n.addr->type == NET_IP4) ? i->addr4 : (i->addr6 ?: i->llv6); + + if (!addr) + { + log(L_ERR "KRT: interface %s has no IP addess", i->name); + return -1; + } + + sockaddr_fill(&gate, af, addr->ip, i, 0); msg.rtm.rtm_addrs |= RTA_GATEWAY; break; } @@ -1124,13 +1127,11 @@ kif_sys_shutdown(struct kif_proto *p) krt_buffer_release(&p->p); } - -struct ifa * -kif_get_primary_ip(struct iface *i UNUSED) +int +kif_update_sysdep_addr(struct iface *i) { -#if 0 static int fd = -1; - + if (fd < 0) fd = socket(AF_INET, SOCK_DGRAM, 0); @@ -1140,20 +1141,10 @@ kif_get_primary_ip(struct iface *i UNUSED) int rv = ioctl(fd, SIOCGIFADDR, (char *) &ifr); if (rv < 0) - return NULL; - - ip_addr addr; - struct sockaddr_in *sin = (struct sockaddr_in *) &ifr.ifr_addr; - memcpy(&addr, &sin->sin_addr.s_addr, sizeof(ip_addr)); - ipa_ntoh(addr); + return 0; - struct ifa *a; - WALK_LIST(a, i->addrs) - { - if (ipa_equal(a->ip, addr)) - return a; - } -#endif + ip4_addr old = i->sysdep; + i->sysdep = ip4_from_ipa(ipa_from_sa4(&ifr.ifr_addr); - return NULL; + return !ip4_equal(i->sysdep, addr); } diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h index 0e895e20..68296e65 100644 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@ -38,12 +38,12 @@ */ #define INIT_MREQ4(maddr,ifa) \ - { .imr_multiaddr = ipa_to_in4(maddr), .imr_interface = ipa_to_in4(ifa->addr->ip) } + { .imr_multiaddr = ipa_to_in4(maddr), .imr_interface = ip4_to_in4(ifa->sysdep) } static inline int sk_setup_multicast4(sock *s) { - struct in_addr ifa = ipa_to_in4(s->iface->addr->ip); + struct in_addr ifa = ip4_to_in4(s->iface->sysdep); u8 ttl = s->ttl; u8 n = 0; diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index 2b7b13fb..c9d5cdec 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -2030,3 +2030,9 @@ void kif_sys_shutdown(struct kif_proto *p UNUSED) { } + +int +kif_update_sysdep_addr(struct iface *i UNUSED) +{ + return 0; +} diff --git a/sysdep/unix/krt.Y b/sysdep/unix/krt.Y index b261c91e..3bf7da65 100644 --- a/sysdep/unix/krt.Y +++ b/sysdep/unix/krt.Y @@ -14,6 +14,7 @@ CF_DEFINES #define THIS_KRT ((struct krt_config *) this_proto) #define THIS_KIF ((struct kif_config *) this_proto) +#define KIF_IFACE ((struct kif_iface_config *) this_ipatt) static void krt_set_merge_paths(struct channel_config *cc, uint merge, uint limit) @@ -25,6 +26,17 @@ krt_set_merge_paths(struct channel_config *cc, uint merge, uint limit) cc->merge_limit = limit; } +static void +kif_set_preferred(ip_addr ip) +{ + if (ipa_is_ip4(ip)) + KIF_IFACE->pref_v4 = ip; + else if (!ipa_is_link_local(ip)) + KIF_IFACE->pref_v6 = ip; + else + KIF_IFACE->pref_ll = ip; +} + CF_DECLS CF_KEYWORDS(KERNEL, PERSIST, SCAN, TIME, LEARN, DEVICE, ROUTES, GRACEFUL, RESTART, KRT_SOURCE, KRT_METRIC, MERGE, PATHS) @@ -88,18 +100,38 @@ CF_ADDTO(kif_proto, kif_proto kif_item ';') kif_item: proto_item + | INTERFACE kif_iface | SCAN TIME expr { /* Scan time of 0 means scan on startup only */ THIS_KIF->scan_time = $3; } - | PRIMARY opttext net_or_ipa { - struct kif_primary_item *kpi = cfg_alloc(sizeof (struct kif_primary_item)); - kpi->pattern = $2; - kpi->addr = $3; - add_tail(&THIS_KIF->primary, &kpi->n); - } ; +kif_iface_start: +{ + this_ipatt = cfg_allocz(sizeof(struct kif_iface_config)); + add_tail(&THIS_KIF->iface_list, NODE this_ipatt); + init_list(&this_ipatt->ipn_list); +} + +kif_iface_item: + PREFERRED ipa { kif_set_preferred($2); } + ; + +kif_iface_opts: + /* empty */ + | kif_iface_opts kif_iface_item ';' + ; + +kif_iface_opt_list: + /* empty */ + | '{' kif_iface_opts '}' + ; + +kif_iface: + kif_iface_start iface_patt_list_nopx kif_iface_opt_list; + + CF_ADDTO(dynamic_attr, KRT_SOURCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_KRT_SOURCE); }) CF_ADDTO(dynamic_attr, KRT_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_KRT_METRIC); }) diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index f0241777..0349a09f 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -89,6 +89,16 @@ static struct kif_config *kif_cf; static timer *kif_scan_timer; static bird_clock_t kif_last_shot; +static struct kif_iface_config kif_default_iface = {}; + +struct kif_iface_config * +kif_get_iface_config(struct iface *iface) +{ + struct kif_config *cf = (void *) (kif_proto->p.cf); + struct kif_iface_config *ic = (void *) iface_patt_find(&cf->iface_list, iface, NULL); + return ic ?: &kif_default_iface; +} + static void kif_scan(timer *t) { @@ -116,57 +126,6 @@ kif_request_scan(void) tm_start(kif_scan_timer, 1); } -static inline int -prefer_addr(struct ifa *a, struct ifa *b) -{ - int sa = a->scope > SCOPE_LINK; - int sb = b->scope > SCOPE_LINK; - - if (sa < sb) - return 0; - else if (sa > sb) - return 1; - else - return ipa_compare(a->ip, b->ip) < 0; -} - -static inline struct ifa * -find_preferred_ifa(struct iface *i, const net_addr *n) -{ - struct ifa *a, *b = NULL; - - WALK_LIST(a, i->addrs) - { - if (!(a->flags & IA_SECONDARY) && - (!n || ipa_in_netX(a->ip, n)) && - (!b || prefer_addr(a, b))) - b = a; - } - - return b; -} - -struct ifa * -kif_choose_primary(struct iface *i) -{ - struct kif_config *cf = (struct kif_config *) (kif_proto->p.cf); - struct kif_primary_item *it; - struct ifa *a; - - WALK_LIST(it, cf->primary) - { - if (!it->pattern || patmatch(it->pattern, i->name)) - if (a = find_preferred_ifa(i, &it->addr)) - return a; - } - - if (a = kif_get_primary_ip(i)) - return a; - - return find_preferred_ifa(i, NULL); -} - - static struct proto * kif_init(struct proto_config *c) { @@ -224,15 +183,15 @@ kif_reconfigure(struct proto *p, struct proto_config *new) tm_start(kif_scan_timer, n->scan_time); } - if (!EMPTY_LIST(o->primary) || !EMPTY_LIST(n->primary)) + if (!EMPTY_LIST(o->iface_list) || !EMPTY_LIST(n->iface_list)) { /* This is hack, we have to update a configuration * to the new value just now, because it is used - * for recalculation of primary addresses. + * for recalculation of preferred addresses. */ p->cf = new; - ifa_recalc_all_primary_addresses(); + if_recalc_all_preferred_addresses(); } return 1; @@ -254,7 +213,7 @@ kif_init_config(int class) kif_cf = (struct kif_config *) proto_config_new(&proto_unix_iface, class); kif_cf->scan_time = 60; - init_list(&kif_cf->primary); + init_list(&kif_cf->iface_list); kif_sys_init_config(kif_cf); return (struct proto_config *) kif_cf; @@ -266,14 +225,13 @@ kif_copy_config(struct proto_config *dest, struct proto_config *src) struct kif_config *d = (struct kif_config *) dest; struct kif_config *s = (struct kif_config *) src; - /* Copy primary addr list */ - cfg_copy_list(&d->primary, &s->primary, sizeof(struct kif_primary_item)); + /* Copy interface config list */ + cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct kif_iface_config)); /* Fix sysdep parts */ kif_sys_copy_config(d, s); } - struct protocol proto_unix_iface = { .name = "Device", .template = "device%d", diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h index cb404de3..089c97ad 100644 --- a/sysdep/unix/krt.h +++ b/sysdep/unix/krt.h @@ -94,17 +94,20 @@ void krt_got_route_async(struct krt_proto *p, struct rte *e, int new); extern struct protocol proto_unix_iface; -struct kif_primary_item { - node n; - byte *pattern; - net_addr addr; -}; - struct kif_config { struct proto_config c; struct kif_params sys; /* Sysdep params */ + + list iface_list; /* List of iface configs (struct kif_iface_config) */ int scan_time; /* How often we re-scan interfaces */ - list primary; /* Preferences for primary addresses (struct kif_primary_item) */ +}; + +struct kif_iface_config { + struct iface_patt i; + + ip_addr pref_v4; + ip_addr pref_v6; + ip_addr pref_ll; }; struct kif_proto { @@ -116,6 +119,7 @@ extern struct kif_proto *kif_proto; #define KIF_CF ((struct kif_config *)p->p.cf) +struct kif_iface_config * kif_get_iface_config(struct iface *iface); struct proto_config * krt_init_config(int class); @@ -150,6 +154,6 @@ void kif_sys_copy_config(struct kif_config *, struct kif_config *); void kif_do_scan(struct kif_proto *); -struct ifa *kif_get_primary_ip(struct iface *i); +int kif_update_sysdep_addr(struct iface *i); #endif diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h index dcaab729..4b0fb005 100644 --- a/sysdep/unix/unix.h +++ b/sysdep/unix/unix.h @@ -80,6 +80,9 @@ static inline ip_addr ipa_from_sa(sockaddr *sa) static inline struct in_addr ipa_to_in4(ip_addr a) { return (struct in_addr) { htonl(ipa_to_u32(a)) }; } +static inline struct in_addr ip4_to_in4(ip4_addr a) +{ return (struct in_addr) { htonl(ip4_to_u32(a)) }; } + static inline struct in6_addr ipa_to_in6(ip_addr a) { return (struct in6_addr) { .s6_addr32 = { htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a)) } }; } |