libnl: /data/src/libnl3/lib/route/mdb.c Source File

libnl 3.10.0

mdb.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2/*
3 * lib/route/mdb.c Multicast Database
4 */
5
6#include "nl-default.h"
7
8#include <linux/if_bridge.h>
9
10#include <netlink/netlink.h>
11#include <netlink/route/mdb.h>
12#include <netlink/route/nexthop.h>
13#include <netlink/utils.h>
14#include <netlink/route/rtnl.h>
15
16#include "nl-route.h"
17#include "nl-aux-route/nl-route.h"
18#include "nl-priv-dynamic-core/object-api.h"
19#include "nl-priv-dynamic-core/cache-api.h"
20
21/** @cond SKIP */
22#define MDB_ATTR_IFINDEX 0x000001
23#define MDB_ATTR_ENTRIES 0x000002
24
25struct rtnl_mdb {
26 NLHDR_COMMON
27 uint32_t ifindex;
28
29 struct nl_list_head mdb_entry_list;
30};
31
32struct rtnl_mdb_entry {
33 struct nl_list_head mdb_list;
34 struct nl_addr *addr;
35 uint32_t ifindex;
36 uint16_t vid;
37 uint16_t proto;
38 uint8_t state;
39};
40
41static struct rtnl_mdb_entry *rtnl_mdb_entry_alloc(void);
42static void rtnl_mdb_entry_free(struct rtnl_mdb_entry *mdb_entry);
43
44static struct nl_cache_ops rtnl_mdb_ops;
45static struct nl_object_ops mdb_obj_ops;
46/** @endcond */
47
48static void mdb_constructor(struct nl_object *obj)
49{
50 struct rtnl_mdb *_mdb = (struct rtnl_mdb *) obj;
51
52 nl_init_list_head(&_mdb->mdb_entry_list);
53}
54
55static void mdb_free_data(struct nl_object *obj)
56{
57 struct rtnl_mdb *mdb = (struct rtnl_mdb *)obj;
58 struct rtnl_mdb_entry *mdb_entry;
59 struct rtnl_mdb_entry *mdb_entry_safe;
60
61 nl_list_for_each_entry_safe(mdb_entry, mdb_entry_safe,
62 &mdb->mdb_entry_list, mdb_list)
63 rtnl_mdb_entry_free(mdb_entry);
64}
65
66static int mdb_entry_equal(struct rtnl_mdb_entry *a, struct rtnl_mdb_entry *b)
67{
68 return a->ifindex == b->ifindex
69 && a->vid == b->vid
70 && a->proto == b->proto
71 && a->state == b->state
72 && nl_addr_cmp(a->addr, b->addr) == 0;
73}
74
75static uint64_t mdb_compare(struct nl_object *_a, struct nl_object *_b,
76 uint64_t attrs, int flags)
77{
78 struct rtnl_mdb *a = (struct rtnl_mdb *) _a;
79 struct rtnl_mdb *b = (struct rtnl_mdb *) _b;
80 struct rtnl_mdb_entry *a_entry, *b_entry;
81 uint64_t diff = 0;
82
83#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
84 diff |= _DIFF(MDB_ATTR_IFINDEX, a->ifindex != b->ifindex);
85#undef _DIFF
86
87 a_entry = nl_list_entry(a->mdb_entry_list.next, struct rtnl_mdb_entry, mdb_list);
88 b_entry = nl_list_entry(b->mdb_entry_list.next, struct rtnl_mdb_entry, mdb_list);
89 while (1) {
90 if ( &a_entry->mdb_list == &a->mdb_entry_list
91 || &b_entry->mdb_list == &b->mdb_entry_list) {
92 if ( &a_entry->mdb_list != &a->mdb_entry_list
93 || &b_entry->mdb_list != &b->mdb_entry_list)
94 diff |= MDB_ATTR_ENTRIES;
95 break;
96 }
97 if (!mdb_entry_equal(a_entry, b_entry)) {
98 diff |= MDB_ATTR_ENTRIES;
99 break;
100 }
101 a_entry = nl_list_entry(a_entry->mdb_list.next, struct rtnl_mdb_entry, mdb_list);
102 b_entry = nl_list_entry(b_entry->mdb_list.next, struct rtnl_mdb_entry, mdb_list);
103 }
104
105 return diff;
106}
107
108static struct rtnl_mdb_entry *mdb_entry_clone(struct rtnl_mdb_entry *src)
109{
110 struct rtnl_mdb_entry *dst = rtnl_mdb_entry_alloc();
111 if (!dst)
112 return NULL;
113
114 dst->ifindex = src->ifindex;
115 dst->state = src->state;
116 dst->vid = src->vid;
117 dst->proto = src->proto;
118
119 dst->addr = nl_addr_clone(src->addr);
120 if (dst->addr == NULL) {
121 free(dst);
122 return NULL;
123 }
124
125 return dst;
126}
127
128static int mdb_clone(struct nl_object *_dst, struct nl_object *_src)
129{
130 struct rtnl_mdb *dst = nl_object_priv(_dst);
131 struct rtnl_mdb *src = nl_object_priv(_src);
132 struct rtnl_mdb_entry *entry;
133
134 nl_init_list_head(&dst->mdb_entry_list);
135
136 nl_list_for_each_entry(entry, &src->mdb_entry_list, mdb_list) {
137 struct rtnl_mdb_entry *copy = mdb_entry_clone(entry);
138
139 if (!copy)
140 return -NLE_NOMEM;
141
142 rtnl_mdb_add_entry(dst, copy);
143 }
144
145 return 0;
146}
147
148static int mdb_update(struct nl_object *old_obj, struct nl_object *new_obj)
149{
150 struct rtnl_mdb *old = (struct rtnl_mdb *) old_obj;
151 struct rtnl_mdb *new = (struct rtnl_mdb *) new_obj;
152 struct rtnl_mdb_entry *entry, *old_entry;
153 int action = new_obj->ce_msgtype;
154
155 if (new->ifindex != old->ifindex)
156 return -NLE_OPNOTSUPP;
157
158 switch (action) {
159 case RTM_NEWMDB:
160 nl_list_for_each_entry(entry, &new->mdb_entry_list, mdb_list) {
161 struct rtnl_mdb_entry *copy = mdb_entry_clone(entry);
162
163 if (!copy)
164 return -NLE_NOMEM;
165
166 rtnl_mdb_add_entry(old, copy);
167 }
168 break;
169 case RTM_DELMDB:
170 entry = nl_list_first_entry(&new->mdb_entry_list,
171 struct rtnl_mdb_entry,
172 mdb_list);
173 nl_list_for_each_entry(old_entry, &old->mdb_entry_list, mdb_list) {
174 if ( old_entry->ifindex == entry->ifindex
175 && !nl_addr_cmp(old_entry->addr, entry->addr)) {
176 nl_list_del(&old_entry->mdb_list);
177 break;
178 }
179 }
180 break;
181 }
182
183 return NLE_SUCCESS;
184}
185
186static struct nla_policy mdb_policy[MDBA_MAX + 1] = {
187 [MDBA_MDB] = {.type = NLA_NESTED},
188};
189
190static struct nla_policy mdb_db_policy[MDBA_MDB_MAX + 1] = {
191 [MDBA_MDB_ENTRY] = {.type = NLA_NESTED},
192};
193
194static int mdb_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
195 struct nlmsghdr *nlh, struct nl_parser_param *pp)
196{
197 int err = 0;
198 int rem = 0;
199 struct nlattr *tb[MDBA_MAX + 1];
200 struct br_port_msg *port;
201 struct nlattr *nla;
202 struct br_mdb_entry *e;
203 _nl_auto_rtnl_mdb struct rtnl_mdb *mdb = rtnl_mdb_alloc();
204
205 if (!mdb)
206 return -NLE_NOMEM;
207
208 err = nlmsg_parse(nlh, sizeof(struct br_port_msg), tb, MDBA_MAX,
209 mdb_policy);
210 if (err < 0)
211 return err;
212
213 mdb->ce_msgtype = nlh->nlmsg_type;
214
215 port = nlmsg_data(nlh);
216 mdb->ifindex = port->ifindex;
217 mdb->ce_mask |= MDB_ATTR_IFINDEX;
218
219 if (tb[MDBA_MDB]) {
220 struct nlattr *db_attr[MDBA_MDB_MAX+1];
221
222 err = nla_parse_nested(db_attr, MDBA_MDB_MAX, tb[MDBA_MDB],
223 mdb_db_policy);
224 if (err < 0)
225 return err;
226 rem = nla_len(tb[MDBA_MDB]);
227
228 for (nla = nla_data(tb[MDBA_MDB]); nla_ok(nla, rem);
229 nla = nla_next(nla, &rem)) {
230 int rm = nla_len(nla);
231 struct nlattr *nla2;
232
233 for (nla2 = nla_data(nla); nla_ok(nla2, rm);
234 nla2 = nla_next(nla2, &rm)) {
235 _nl_auto_nl_addr struct nl_addr *addr = NULL;
236 struct rtnl_mdb_entry *entry;
237 uint16_t proto;
238
239 e = nla_data(nla2);
240
241 proto = ntohs(e->addr.proto);
242
243 if (proto == ETH_P_IP) {
244 addr = nl_addr_build(
245 AF_INET, &e->addr.u.ip4,
246 sizeof(e->addr.u.ip4));
247 } else if (proto == ETH_P_IPV6) {
248 addr = nl_addr_build(
249 AF_INET6, &e->addr.u.ip6,
250 sizeof(e->addr.u.ip6));
251 } else {
252 addr = nl_addr_build(
253 AF_LLC, e->addr.u.mac_addr,
254 sizeof(e->addr.u.mac_addr));
255 }
256 if (!addr)
257 return -NLE_NOMEM;
258
259 entry = rtnl_mdb_entry_alloc();
260 if (!entry)
261 return -NLE_NOMEM;
262
263 mdb->ce_mask |= MDB_ATTR_ENTRIES;
264
265 entry->ifindex = e->ifindex;
266 entry->vid = e->vid;
267 entry->state = e->state;
268 entry->proto = ntohs(e->addr.proto);
269 entry->addr = _nl_steal_pointer(&addr);
270 rtnl_mdb_add_entry(mdb, entry);
271 }
272 }
273 }
274
275 return pp->pp_cb((struct nl_object *) mdb, pp);
276}
277
278static int mdb_request_update(struct nl_cache *cache, struct nl_sock *sk)
279{
280 return nl_rtgen_request(sk, RTM_GETMDB, AF_BRIDGE, NLM_F_DUMP);
281}
282
283static void mdb_entry_dump_line(struct rtnl_mdb_entry *entry,
284 struct nl_dump_params *p)
285{
286 char buf[INET6_ADDRSTRLEN];
287
288 nl_dump(p, "port %d ", entry->ifindex);
289 nl_dump(p, "vid %d ", entry->vid);
290 nl_dump(p, "proto 0x%04x ", entry->proto);
291 nl_dump(p, "address %s\n", nl_addr2str(entry->addr, buf, sizeof(buf)));
292}
293
294static void mdb_dump_line(struct nl_object *obj, struct nl_dump_params *p)
295{
296 struct rtnl_mdb *mdb = (struct rtnl_mdb *) obj;
297 struct rtnl_mdb_entry *_mdb;
298
299 nl_dump(p, "dev %d \n", mdb->ifindex);
300
301 nl_list_for_each_entry(_mdb, &mdb->mdb_entry_list, mdb_list) {
302 p->dp_ivar = NH_DUMP_FROM_ONELINE;
303 mdb_entry_dump_line(_mdb, p);
304 }
305}
306
307static void mdb_dump_details(struct nl_object *obj, struct nl_dump_params *p)
308{
309 mdb_dump_line(obj, p);
310}
311
312static void mdb_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
313{
314 mdb_dump_details(obj, p);
315}
316
317void rtnl_mdb_put(struct rtnl_mdb *mdb)
318{
319 nl_object_put((struct nl_object *) mdb);
320}
321
322/** @} */
323
324/**
325 * @name Cache Management
326 * @{
327 */
328int rtnl_mdb_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
329{
330 return nl_cache_alloc_and_fill(&rtnl_mdb_ops, sk, result);
331}
332
333/**
334 * Build a neighbour cache including all MDB entries currently configured in the kernel.
335 * @arg sock Netlink socket.
336 * @arg result Pointer to store resulting cache.
337 * @arg flags Flags to apply to cache before filling
338 *
339 * Allocates a new MDB cache, initializes it properly and updates it
340 * to include all Multicast Database entries currently configured in the kernel.
341 *
342 * @return 0 on success or a negative error code.
343 */
344int rtnl_mdb_alloc_cache_flags(struct nl_sock *sock, struct nl_cache **result,
345 unsigned int flags)
346{
347 struct nl_cache *cache;
348 int err;
349
350 cache = nl_cache_alloc(&rtnl_mdb_ops);
351 if (!cache)
352 return -NLE_NOMEM;
353
354 nl_cache_set_flags(cache, flags);
355
356 if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
357 nl_cache_free(cache);
358 return err;
359 }
360
361 *result = cache;
362 return 0;
363}
364
365/** @} */
366
367/**
368 * @name Attributes
369 * @{
370 */
371uint32_t rtnl_mdb_get_ifindex(struct rtnl_mdb *mdb)
372{
373 return mdb->ifindex;
374}
375
376void rtnl_mdb_add_entry(struct rtnl_mdb *mdb, struct rtnl_mdb_entry *entry)
377{
378 nl_list_add_tail(&entry->mdb_list, &mdb->mdb_entry_list);
379}
380
381void rtnl_mdb_foreach_entry(struct rtnl_mdb *mdb,
382 void (*cb)(struct rtnl_mdb_entry *, void *),
383 void *arg)
384{
385 struct rtnl_mdb_entry *entry;
386
387 nl_list_for_each_entry(entry, &mdb->mdb_entry_list, mdb_list) {
388 cb(entry, arg);
389 }
390}
391
392int rtnl_mdb_entry_get_ifindex(struct rtnl_mdb_entry *mdb_entry)
393{
394 return mdb_entry->ifindex;
395}
396
397int rtnl_mdb_entry_get_vid(struct rtnl_mdb_entry *mdb_entry)
398{
399 return mdb_entry->vid;
400}
401
402int rtnl_mdb_entry_get_state(struct rtnl_mdb_entry *mdb_entry)
403{
404 return mdb_entry->state;
405}
406
407struct nl_addr *rtnl_mdb_entry_get_addr(struct rtnl_mdb_entry *mdb_entry)
408{
409 return mdb_entry->addr;
410}
411
412uint16_t rtnl_mdb_entry_get_proto(struct rtnl_mdb_entry *mdb_entry)
413{
414 return mdb_entry->proto;
415}
416
417/** @} */
418
419static struct nl_object_ops mdb_obj_ops = {
420 .oo_name = "route/mdb",
421 .oo_size = sizeof(struct rtnl_mdb),
422 .oo_constructor = mdb_constructor,
423 .oo_dump = {
424 [NL_DUMP_LINE] = mdb_dump_line,
425 [NL_DUMP_DETAILS] = mdb_dump_details,
426 [NL_DUMP_STATS] = mdb_dump_stats,
427 },
428 .oo_clone = mdb_clone,
429 .oo_compare = mdb_compare,
430 .oo_update = mdb_update,
431 .oo_free_data = mdb_free_data,
432};
433
434struct rtnl_mdb *rtnl_mdb_alloc(void)
435{
436 return (struct rtnl_mdb *) nl_object_alloc(&mdb_obj_ops);
437}
438
439static struct rtnl_mdb_entry *rtnl_mdb_entry_alloc(void)
440{
441 struct rtnl_mdb_entry *mdb;
442
443 mdb = calloc(1, sizeof(struct rtnl_mdb_entry));
444 if (!mdb)
445 return NULL;
446
447 nl_init_list_head(&mdb->mdb_list);
448
449 return mdb;
450
451}
452
453static void rtnl_mdb_entry_free(struct rtnl_mdb_entry *mdb_entry)
454{
455 nl_list_del(&mdb_entry->mdb_list);
456 nl_addr_put(mdb_entry->addr);
457 free(mdb_entry);
458}
459
460static struct nl_af_group mdb_groups[] = {
461 {AF_BRIDGE, RTNLGRP_MDB},
462 {END_OF_GROUP_LIST},
463};
464
465static struct nl_cache_ops rtnl_mdb_ops = {
466 .co_name = "route/mdb",
467 .co_hdrsize = sizeof(struct br_port_msg),
468 .co_msgtypes = {
469 { RTM_NEWMDB, NL_ACT_NEW, "new"},
470 { RTM_DELMDB, NL_ACT_DEL, "del"},
471 { RTM_GETMDB, NL_ACT_GET, "get"},
472 END_OF_MSGTYPES_LIST,
473 },
474 .co_protocol = NETLINK_ROUTE,
475 .co_groups = mdb_groups,
476 .co_request_update = mdb_request_update,
477 .co_msg_parser = mdb_msg_parser,
478 .co_obj_ops = &mdb_obj_ops,
479};
480
481static void _nl_init mdb_init(void)
482{
483 nl_cache_mngt_register(&rtnl_mdb_ops);
484}
485
486static void _nl_exit mdb_exit(void)
487{
488 nl_cache_mngt_unregister(&rtnl_mdb_ops);
489}
490
491/** @} */
nl_addr_build
struct nl_addr * nl_addr_build(int family, const void *buf, size_t size)
Allocate abstract address based on a binary address.
Definition addr.c:216
nl_addr_cmp
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
Definition addr.c:587
nl_addr_clone
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
Definition addr.c:495
nl_addr2str
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
Definition addr.c:1001
nl_addr_put
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
Definition addr.c:541
nla_next
struct nlattr * nla_next(const struct nlattr *nla, int *remaining)
Return next attribute in a stream of attributes.
Definition attr.c:172
nla_ok
int nla_ok(const struct nlattr *nla, int remaining)
Check if the attribute header and payload can be accessed safely.
Definition attr.c:147
nla_data
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
Definition attr.c:119
nla_parse_nested
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition attr.c:1035
nla_len
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition attr.c:130
NLA_NESTED
@ NLA_NESTED
Nested attributes.
Definition attr.h:42
nl_cache_mngt_unregister
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
Definition cache_mngt.c:287
nl_cache_mngt_register
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
Definition cache_mngt.c:252
nl_cache_refill
int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
(Re)fill a cache with the contents in the kernel.
Definition cache.c:1041
nl_cache_set_flags
void nl_cache_set_flags(struct nl_cache *cache, unsigned int flags)
Set cache flags.
Definition cache.c:614
nl_cache_free
void nl_cache_free(struct nl_cache *cache)
Free a cache.
Definition cache.c:409
nl_cache_alloc
struct nl_cache * nl_cache_alloc(struct nl_cache_ops *ops)
Allocate new cache.
Definition cache.c:184
nl_cache_alloc_and_fill
int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock, struct nl_cache **result)
Allocate new cache and fill it.
Definition cache.c:234
nlmsg_data
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
Definition msg.c:108
nlmsg_parse
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy)
parse attributes of a netlink message
Definition msg.c:219
nl_object_put
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
Definition object.c:221
nl_object_alloc
struct nl_object * nl_object_alloc(struct nl_object_ops *ops)
Allocate a new object of kind specified by the operations handle.
Definition object.c:55
nl_rtgen_request
int nl_rtgen_request(struct nl_sock *sk, int type, int family, int flags)
Send routing netlink request message.
Definition rtnl.c:38
nl_dump
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition utils.c:1015
NL_DUMP_STATS
@ NL_DUMP_STATS
Dump all attributes including statistics.
Definition types.h:22
NL_DUMP_LINE
@ NL_DUMP_LINE
Dump object briefly on one line.
Definition types.h:20
NL_DUMP_DETAILS
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition types.h:21
nl_dump_params
Dumping parameters.
Definition types.h:32
nl_dump_params::dp_ivar
int dp_ivar
PRIVATE Owned by the current caller.
Definition types.h:103
nl_list_head
Definition list.h:16
nla_policy
Attribute validation policy.
Definition attr.h:63
nla_policy::type
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition attr.h:65