diff options
author | Timo Teräs <timo.teras@iki.fi> | 2015-12-25 10:32:11 +0200 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2016-03-30 16:59:22 +0300 |
commit | 068e64859913c6844bbe6703815a633175650547 (patch) | |
tree | 3efc0440477560ac6211f9da3bea3f812bb05270 /nhrpd/nhrp_vc.c | |
parent | 76aaa0456a3804a0a1d2948d9a391383b62cbe37 (diff) | |
download | quagga-068e64859913c6844bbe6703815a633175650547.tar.bz2 quagga-068e64859913c6844bbe6703815a633175650547.tar.xz |
initial implementation of nhrpnhrp
this is nhrp changes from commit c321432aef01e13116980983f0a50ba486505804
rebased on quagga master and updated for vrf changes
Diffstat (limited to 'nhrpd/nhrp_vc.c')
-rw-r--r-- | nhrpd/nhrp_vc.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/nhrpd/nhrp_vc.c b/nhrpd/nhrp_vc.c new file mode 100644 index 00000000..f9e1ee06 --- /dev/null +++ b/nhrpd/nhrp_vc.c @@ -0,0 +1,217 @@ +/* NHRP virtual connection + * Copyright (c) 2014-2015 Timo Teräs + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + */ + +#include "zebra.h" +#include "memory.h" +#include "stream.h" +#include "hash.h" +#include "thread.h" +#include "jhash.h" + +#include "nhrpd.h" +#include "os.h" + +struct child_sa { + uint32_t id; + struct nhrp_vc *vc; + struct list_head childlist_entry; +}; + +static struct hash *nhrp_vc_hash; +static struct list_head childlist_head[512]; + +static unsigned int nhrp_vc_key(void *peer_data) +{ + struct nhrp_vc *vc = peer_data; + return jhash_2words( + sockunion_hash(&vc->local.nbma), + sockunion_hash(&vc->remote.nbma), + 0); +} + +static int nhrp_vc_cmp(const void *cache_data, const void *key_data) +{ + const struct nhrp_vc *a = cache_data; + const struct nhrp_vc *b = key_data; + return sockunion_same(&a->local.nbma, &b->local.nbma) && + sockunion_same(&a->remote.nbma, &b->remote.nbma); +} + +static void *nhrp_vc_alloc(void *data) +{ + struct nhrp_vc *vc, *key = data; + + vc = XMALLOC(MTYPE_NHRP_VC, sizeof(struct nhrp_vc)); + if (vc) { + *vc = (struct nhrp_vc) { + .local.nbma = key->local.nbma, + .remote.nbma = key->remote.nbma, + .notifier_list = NOTIFIER_LIST_INITIALIZER(&vc->notifier_list), + }; + } + + return vc; +} + +static void nhrp_vc_free(void *data) +{ + XFREE(MTYPE_NHRP_VC, data); +} + +struct nhrp_vc *nhrp_vc_get(const union sockunion *src, const union sockunion *dst, int create) +{ + struct nhrp_vc key; + key.local.nbma = *src; + key.remote.nbma = *dst; + return hash_get(nhrp_vc_hash, &key, create ? nhrp_vc_alloc : 0); +} + +static void nhrp_vc_check_delete(struct nhrp_vc *vc) +{ + if (vc->updating || vc->ipsec || notifier_active(&vc->notifier_list)) + return; + hash_release(nhrp_vc_hash, vc); + nhrp_vc_free(vc); +} + +static void nhrp_vc_update(struct nhrp_vc *vc, long cmd) +{ + vc->updating = 1; + notifier_call(&vc->notifier_list, cmd); + vc->updating = 0; + nhrp_vc_check_delete(vc); +} + +static void nhrp_vc_ipsec_reset(struct nhrp_vc *vc) +{ + vc->local.id[0] = 0; + vc->local.certlen = 0; + vc->remote.id[0] = 0; + vc->remote.certlen = 0; +} + +int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc) +{ + char buf[2][SU_ADDRSTRLEN]; + struct child_sa *sa = NULL, *lsa; + uint32_t child_hash = child_id % ZEBRA_NUM_OF(childlist_head); + int abort_migration = 0; + + list_for_each_entry(lsa, &childlist_head[child_hash], childlist_entry) { + if (lsa->id == child_id) { + sa = lsa; + break; + } + } + + if (!sa) { + if (!vc) return 0; + + sa = XMALLOC(MTYPE_NHRP_VC, sizeof(struct child_sa)); + if (!sa) return 0; + + *sa = (struct child_sa) { + .id = child_id, + .childlist_entry = LIST_INITIALIZER(sa->childlist_entry), + .vc = NULL, + }; + list_add_tail(&sa->childlist_entry, &childlist_head[child_hash]); + } + + if (sa->vc == vc) + return 0; + + if (vc) { + /* Attach first to new VC */ + vc->ipsec++; + nhrp_vc_update(vc, NOTIFY_VC_IPSEC_CHANGED); + } + if (sa->vc && vc) { + /* Notify old VC of migration */ + sa->vc->abort_migration = 0; + debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %s to %s", + sockunion2str(&sa->vc->remote.nbma, buf[0], sizeof buf[0]), + sockunion2str(&vc->remote.nbma, buf[1], sizeof buf[1])); + nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_UPDATE_NBMA); + abort_migration = sa->vc->abort_migration; + } + if (sa->vc) { + /* Deattach old VC */ + sa->vc->ipsec--; + if (!sa->vc->ipsec) nhrp_vc_ipsec_reset(sa->vc); + nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_CHANGED); + } + + /* Update */ + sa->vc = vc; + if (!vc) { + list_del(&sa->childlist_entry); + XFREE(MTYPE_NHRP_VC, sa); + } + + return abort_migration; +} + +void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n, notifier_fn_t action) +{ + notifier_add(n, &vc->notifier_list, action); +} + +void nhrp_vc_notify_del(struct nhrp_vc *vc, struct notifier_block *n) +{ + notifier_del(n); + nhrp_vc_check_delete(vc); +} + + +struct nhrp_vc_iterator_ctx { + void (*cb)(struct nhrp_vc *, void *); + void *ctx; +}; + +static void nhrp_vc_iterator(struct hash_backet *b, void *ctx) +{ + struct nhrp_vc_iterator_ctx *ic = ctx; + ic->cb(b->data, ic->ctx); +} + +void nhrp_vc_foreach(void (*cb)(struct nhrp_vc *, void *), void *ctx) +{ + struct nhrp_vc_iterator_ctx ic = { + .cb = cb, + .ctx = ctx, + }; + hash_iterate(nhrp_vc_hash, nhrp_vc_iterator, &ic); +} + +void nhrp_vc_init(void) +{ + size_t i; + + nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp); + for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) + list_init(&childlist_head[i]); +} + +void nhrp_vc_reset(void) +{ + struct child_sa *sa, *n; + size_t i; + + for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) { + list_for_each_entry_safe(sa, n, &childlist_head[i], childlist_entry) + nhrp_vc_ipsec_updown(sa->id, 0); + } +} + +void nhrp_vc_terminate(void) +{ + nhrp_vc_reset(); + hash_clean(nhrp_vc_hash, nhrp_vc_free); +} |