-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
*/
vlist_flush_all(&net->services);
}
+static int
+__service_add_member(struct network_host **list, int *n, struct network_host *member)
+{
+ int i;
+
+ for (i = 0; i < *n; i++) {
+ if (list[i] == member)
+ return 0;
+ }
+
+ list[(*n)++] = member;
+ return 1;
+}
+
+static int
+__service_add_group(struct network_host **list, int *n, struct network_group *group)
+{
+ int i, count = 0;
+
+ for (i = 0; i < group->n_members; i++)
+ count += __service_add_member(list, n, group->members[i]);
+
+ return count;
+}
+
static int
__service_parse_members(struct network *net, struct network_service *s,
const char *name)
return 0;
if (s)
- s->members[s->n_members++] = host;
+ __service_add_member(s->members, &s->n_members, host);
return 1;
}
if (!group)
return 0;
- if (s) {
- memcpy(&s->members[s->n_members], group->members,
- group->n_members * sizeof(group->members[0]));
- s->n_members += group->n_members;
- }
-
- return group->n_members;
+ if (s)
+ return __service_add_group(s->members, &s->n_members, group);
+ else
+ return group->n_members;
}
static int
s->type = strcpy(type_buf, type);
if (config)
s->config = memcpy(config_buf, config, blob_pad_len(config));
+#ifdef VXLAN_SUPPORT
+ if (type && !strcmp(type, "vxlan"))
+ s->ops = &vxlan_ops;
+#endif
service_parse_members(net, s, tb[SERVICE_ATTR_MEMBERS]);
vlist_add(&net->services, &s->node, name_buf);
service_update(struct vlist_tree *tree, struct vlist_node *node_new,
struct vlist_node *node_old)
{
- struct network_service *s_old;
+ struct network *net = container_of(tree, struct network, services);
+ struct network_service *s_old, *s_new;
+ s_new = container_of_safe(node_new, struct network_service, node);
s_old = container_of_safe(node_old, struct network_service, node);
- if (s_old)
- free(s_old);
+
+ if (s_new && s_old && s_new->ops && s_new->ops == s_old->ops) {
+ s_new->ops->init(net, s_new, s_old);
+ goto out;
+ }
+
+ if (s_new && s_new->ops)
+ s_new->ops->init(net, s_new, NULL);
+
+ if (s_old && s_old->ops)
+ s_old->ops->free(net, s_old);
+
+out:
+ free(s_old);
+}
+
+void network_services_peer_update(struct network *net, struct network_peer *peer)
+{
+ struct network_service *s;
+
+ vlist_for_each_element(&net->services, s, node) {
+ if (!s->ops || !s->ops->peer_update)
+ continue;
+
+ s->ops->peer_update(net, s, peer);
+ }
}
void network_services_init(struct network *net)