1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
5 #include <libubox/avl-cmp.h>
15 static const struct blobmsg_policy service_policy
[__SERVICE_ATTR_MAX
] = {
16 [SERVICE_ATTR_TYPE
] = { "type", BLOBMSG_TYPE_STRING
},
17 [SERVICE_ATTR_CONFIG
] = { "config", BLOBMSG_TYPE_TABLE
},
18 [SERVICE_ATTR_MEMBERS
] = { "members", BLOBMSG_TYPE_ARRAY
},
21 void network_services_free(struct network
*net
)
23 vlist_flush_all(&net
->services
);
27 __service_add_member(struct network_host
**list
, int *n
, struct network_host
*member
)
31 for (i
= 0; i
< *n
; i
++) {
32 if (list
[i
] == member
)
36 list
[(*n
)++] = member
;
41 __service_add_group(struct network_host
**list
, int *n
, struct network_group
*group
)
45 for (i
= 0; i
< group
->n_members
; i
++)
46 count
+= __service_add_member(list
, n
, group
->members
[i
]);
52 __service_parse_members(struct network
*net
, struct network_service
*s
,
55 struct network_group
*group
;
56 struct network_host
*host
;
59 host
= avl_find_element(&net
->hosts
, name
, host
, node
);
65 __service_add_member(s
->members
, &s
->n_members
, host
);
71 group
= avl_find_element(&net
->groups
, name
, group
, node
);
76 return __service_add_group(s
->members
, &s
->n_members
, group
);
78 return group
->n_members
;
82 service_parse_members(struct network
*net
, struct network_service
*s
,
83 struct blob_attr
*data
)
85 struct blob_attr
*cur
;
89 blobmsg_for_each_attr(cur
, data
, rem
)
90 n
+= __service_parse_members(net
, s
, blobmsg_get_string(cur
));
96 service_add(struct network
*net
, struct blob_attr
*data
)
98 struct network_service
*s
;
99 struct blob_attr
*tb
[__SERVICE_ATTR_MAX
];
100 struct blob_attr
*cur
, *config
;
101 const char *name
= blobmsg_name(data
);
102 const char *type
= NULL
;
103 char *name_buf
, *type_buf
;
107 blobmsg_parse(service_policy
, __SERVICE_ATTR_MAX
, tb
,
108 blobmsg_data(data
), blobmsg_len(data
));
110 if ((cur
= tb
[SERVICE_ATTR_TYPE
]) != NULL
)
111 type
= blobmsg_get_string(cur
);
113 if (blobmsg_check_array(tb
[SERVICE_ATTR_MEMBERS
], BLOBMSG_TYPE_STRING
) < 0)
116 config
= tb
[SERVICE_ATTR_CONFIG
];
118 n_members
= service_parse_members(net
, NULL
, tb
[SERVICE_ATTR_MEMBERS
]);
119 s
= calloc_a(sizeof(*s
) + n_members
* sizeof(s
->members
[0]),
120 &name_buf
, strlen(name
) + 1,
121 &type_buf
, type
? strlen(type
) + 1 : 0,
122 &config_buf
, config
? blob_pad_len(config
) : 0);
124 strcpy(name_buf
, name
);
126 s
->type
= strcpy(type_buf
, type
);
128 s
->config
= memcpy(config_buf
, config
, blob_pad_len(config
));
130 if (type
&& !strcmp(type
, "vxlan"))
134 service_parse_members(net
, s
, tb
[SERVICE_ATTR_MEMBERS
]);
135 vlist_add(&net
->services
, &s
->node
, name_buf
);
138 void network_services_add(struct network
*net
, struct blob_attr
*data
)
140 struct blob_attr
*cur
;
143 blobmsg_for_each_attr(cur
, data
, rem
)
144 service_add(net
, cur
);
148 service_update(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
149 struct vlist_node
*node_old
)
151 struct network
*net
= container_of(tree
, struct network
, services
);
152 struct network_service
*s_old
, *s_new
;
154 s_new
= container_of_safe(node_new
, struct network_service
, node
);
155 s_old
= container_of_safe(node_old
, struct network_service
, node
);
157 if (s_new
&& s_old
&& s_new
->ops
&& s_new
->ops
== s_old
->ops
) {
158 s_new
->ops
->init(net
, s_new
, s_old
);
162 if (s_new
&& s_new
->ops
)
163 s_new
->ops
->init(net
, s_new
, NULL
);
165 if (s_old
&& s_old
->ops
)
166 s_old
->ops
->free(net
, s_old
);
172 void network_services_peer_update(struct network
*net
, struct network_peer
*peer
)
174 struct network_service
*s
;
176 vlist_for_each_element(&net
->services
, s
, node
) {
177 if (!s
->ops
|| !s
->ops
->peer_update
)
180 s
->ops
->peer_update(net
, s
, peer
);
184 void network_services_init(struct network
*net
)
186 vlist_init(&net
->services
, avl_strcmp
, service_update
);