1 /* NHRP virtual connection
2 * Copyright (c) 2014-2015 Timo Teräs
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
23 struct list_head childlist_entry;
26 static struct hash *nhrp_vc_hash;
27 static struct list_head childlist_head[512];
29 static unsigned int nhrp_vc_key(void *peer_data)
31 struct nhrp_vc *vc = peer_data;
33 sockunion_hash(&vc->local.nbma),
34 sockunion_hash(&vc->remote.nbma),
38 static int nhrp_vc_cmp(const void *cache_data, const void *key_data)
40 const struct nhrp_vc *a = cache_data;
41 const struct nhrp_vc *b = key_data;
42 return sockunion_same(&a->local.nbma, &b->local.nbma) &&
43 sockunion_same(&a->remote.nbma, &b->remote.nbma);
46 static void *nhrp_vc_alloc(void *data)
48 struct nhrp_vc *vc, *key = data;
50 vc = XMALLOC(MTYPE_NHRP_VC, sizeof(struct nhrp_vc));
52 *vc = (struct nhrp_vc) {
53 .local.nbma = key->local.nbma,
54 .remote.nbma = key->remote.nbma,
55 .notifier_list = NOTIFIER_LIST_INITIALIZER(&vc->notifier_list),
62 static void nhrp_vc_free(void *data)
64 XFREE(MTYPE_NHRP_VC, data);
67 struct nhrp_vc *nhrp_vc_get(const union sockunion *src, const union sockunion *dst, int create)
70 key.local.nbma = *src;
71 key.remote.nbma = *dst;
72 return hash_get(nhrp_vc_hash, &key, create ? nhrp_vc_alloc : 0);
75 static void nhrp_vc_check_delete(struct nhrp_vc *vc)
77 if (vc->updating || vc->ipsec || notifier_active(&vc->notifier_list))
79 hash_release(nhrp_vc_hash, vc);
83 static void nhrp_vc_update(struct nhrp_vc *vc, long cmd)
86 notifier_call(&vc->notifier_list, cmd);
88 nhrp_vc_check_delete(vc);
91 static void nhrp_vc_ipsec_reset(struct nhrp_vc *vc)
94 vc->local.certlen = 0;
96 vc->remote.certlen = 0;
99 int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc)
101 char buf[2][SU_ADDRSTRLEN];
102 struct child_sa *sa = NULL, *lsa;
103 uint32_t child_hash = child_id % ZEBRA_NUM_OF(childlist_head);
104 int abort_migration = 0;
106 list_for_each_entry(lsa, &childlist_head[child_hash], childlist_entry) {
107 if (lsa->id == child_id) {
116 sa = XMALLOC(MTYPE_NHRP_VC, sizeof(struct child_sa));
119 *sa = (struct child_sa) {
121 .childlist_entry = LIST_INITIALIZER(sa->childlist_entry),
124 list_add_tail(&sa->childlist_entry, &childlist_head[child_hash]);
131 /* Attach first to new VC */
133 nhrp_vc_update(vc, NOTIFY_VC_IPSEC_CHANGED);
136 /* Notify old VC of migration */
137 sa->vc->abort_migration = 0;
138 debugf(NHRP_DEBUG_COMMON, "IPsec NBMA change of %s to %s",
139 sockunion2str(&sa->vc->remote.nbma, buf[0], sizeof buf[0]),
140 sockunion2str(&vc->remote.nbma, buf[1], sizeof buf[1]));
141 nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_UPDATE_NBMA);
142 abort_migration = sa->vc->abort_migration;
145 /* Deattach old VC */
147 if (!sa->vc->ipsec) nhrp_vc_ipsec_reset(sa->vc);
148 nhrp_vc_update(sa->vc, NOTIFY_VC_IPSEC_CHANGED);
154 list_del(&sa->childlist_entry);
155 XFREE(MTYPE_NHRP_VC, sa);
158 return abort_migration;
161 void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n, notifier_fn_t action)
163 notifier_add(n, &vc->notifier_list, action);
166 void nhrp_vc_notify_del(struct nhrp_vc *vc, struct notifier_block *n)
169 nhrp_vc_check_delete(vc);
173 struct nhrp_vc_iterator_ctx {
174 void (*cb)(struct nhrp_vc *, void *);
178 static void nhrp_vc_iterator(struct hash_backet *b, void *ctx)
180 struct nhrp_vc_iterator_ctx *ic = ctx;
181 ic->cb(b->data, ic->ctx);
184 void nhrp_vc_foreach(void (*cb)(struct nhrp_vc *, void *), void *ctx)
186 struct nhrp_vc_iterator_ctx ic = {
190 hash_iterate(nhrp_vc_hash, nhrp_vc_iterator, &ic);
193 void nhrp_vc_init(void)
197 nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp);
198 for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++)
199 list_init(&childlist_head[i]);
202 void nhrp_vc_reset(void)
204 struct child_sa *sa, *n;
207 for (i = 0; i < ZEBRA_NUM_OF(childlist_head); i++) {
208 list_for_each_entry_safe(sa, n, &childlist_head[i], childlist_entry)
209 nhrp_vc_ipsec_updown(sa->id, 0);
213 void nhrp_vc_terminate(void)
216 hash_clean(nhrp_vc_hash, nhrp_vc_free);