6#include <netlink-private/netlink.h>
7#include <netlink/netlink.h>
8#include <netlink/route/mdb.h>
9#include <netlink/utils.h>
10#include <linux/if_bridge.h>
13#define MDB_ATTR_IFINDEX 0x000001
14#define MDB_ATTR_ENTRIES 0x000002
16static struct rtnl_mdb_entry *rtnl_mdb_entry_alloc(
void);
17static void rtnl_mdb_entry_free(
struct rtnl_mdb_entry *mdb_entry);
19static struct nl_cache_ops rtnl_mdb_ops;
20static struct nl_object_ops mdb_obj_ops;
23static void mdb_constructor(
struct nl_object *obj)
25 struct rtnl_mdb *_mdb = (
struct rtnl_mdb *) obj;
27 nl_init_list_head(&_mdb->mdb_entry_list);
30static void mdb_free_data(
struct nl_object *obj)
32 struct rtnl_mdb *mdb = (
struct rtnl_mdb *)obj;
33 struct rtnl_mdb_entry *mdb_entry;
34 struct rtnl_mdb_entry *mdb_entry_safe;
36 nl_list_for_each_entry_safe(mdb_entry, mdb_entry_safe,
37 &mdb->mdb_entry_list, mdb_list)
38 rtnl_mdb_entry_free(mdb_entry);
41static int mdb_entry_equal(
struct rtnl_mdb_entry *a,
struct rtnl_mdb_entry *b)
43 return a->ifindex == b->ifindex
45 && a->proto == b->proto
46 && a->state == b->state
50static uint64_t mdb_compare(
struct nl_object *_a,
struct nl_object *_b,
51 uint64_t attrs,
int flags)
53 struct rtnl_mdb *a = (
struct rtnl_mdb *) _a;
54 struct rtnl_mdb *b = (
struct rtnl_mdb *) _b;
55 struct rtnl_mdb_entry *a_entry, *b_entry;
58#define MDB_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MDB_ATTR_##ATTR, a, b, EXPR)
59 diff |= MDB_DIFF(IFINDEX, a->ifindex != b->ifindex);
62 a_entry = nl_list_entry(a->mdb_entry_list.next,
struct rtnl_mdb_entry, mdb_list);
63 b_entry = nl_list_entry(b->mdb_entry_list.next,
struct rtnl_mdb_entry, mdb_list);
65 if ( &a_entry->mdb_list == &a->mdb_entry_list
66 || &b_entry->mdb_list == &b->mdb_entry_list) {
67 if ( &a_entry->mdb_list != &a->mdb_entry_list
68 || &b_entry->mdb_list != &b->mdb_entry_list)
69 diff |= MDB_ATTR_ENTRIES;
72 if (!mdb_entry_equal(a_entry, b_entry)) {
73 diff |= MDB_ATTR_ENTRIES;
76 a_entry = nl_list_entry(a_entry->mdb_list.next,
struct rtnl_mdb_entry, mdb_list);
77 b_entry = nl_list_entry(b_entry->mdb_list.next,
struct rtnl_mdb_entry, mdb_list);
83static struct rtnl_mdb_entry *mdb_entry_clone(
struct rtnl_mdb_entry *src)
85 struct rtnl_mdb_entry *dst = rtnl_mdb_entry_alloc();
89 dst->ifindex = src->ifindex;
90 dst->state = src->state;
92 dst->proto = src->proto;
95 if (dst->addr == NULL) {
103static int mdb_clone(
struct nl_object *_dst,
struct nl_object *_src)
105 struct rtnl_mdb *dst = nl_object_priv(_dst);
106 struct rtnl_mdb *src = nl_object_priv(_src);
107 struct rtnl_mdb_entry *entry;
109 nl_init_list_head(&dst->mdb_entry_list);
111 nl_list_for_each_entry(entry, &src->mdb_entry_list, mdb_list) {
112 struct rtnl_mdb_entry *copy = mdb_entry_clone(entry);
117 rtnl_mdb_add_entry(dst, copy);
123static int mdb_update(
struct nl_object *old_obj,
struct nl_object *new_obj)
125 struct rtnl_mdb *old = (
struct rtnl_mdb *) old_obj;
126 struct rtnl_mdb *
new = (
struct rtnl_mdb *) new_obj;
127 struct rtnl_mdb_entry *entry, *old_entry;
128 int action = new_obj->ce_msgtype;
130 if (new->ifindex != old->ifindex)
131 return -NLE_OPNOTSUPP;
135 nl_list_for_each_entry(entry, &new->mdb_entry_list, mdb_list) {
136 struct rtnl_mdb_entry *copy = mdb_entry_clone(entry);
141 rtnl_mdb_add_entry(old, copy);
145 entry = nl_list_first_entry(&new->mdb_entry_list,
146 struct rtnl_mdb_entry,
148 nl_list_for_each_entry(old_entry, &old->mdb_entry_list, mdb_list) {
149 if ( old_entry->ifindex == entry->ifindex
151 nl_list_del(&old_entry->mdb_list);
161static struct nla_policy mdb_policy[MDBA_MAX + 1] = {
165static struct nla_policy mdb_db_policy[MDBA_MDB_MAX + 1] = {
169static int mdb_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
170 struct nlmsghdr *nlh,
struct nl_parser_param *pp)
174 struct nlattr *tb[MDBA_MAX + 1];
175 struct br_port_msg *port;
177 struct br_mdb_entry *e;
178 _nl_auto_rtnl_mdb
struct rtnl_mdb *mdb = rtnl_mdb_alloc();
183 err =
nlmsg_parse(nlh,
sizeof(
struct br_port_msg), tb, MDBA_MAX,
188 mdb->ce_msgtype = nlh->nlmsg_type;
191 mdb->ifindex = port->ifindex;
192 mdb->ce_mask |= MDB_ATTR_IFINDEX;
195 struct nlattr *db_attr[MDBA_MDB_MAX+1];
210 _nl_auto_nl_addr
struct nl_addr *addr = NULL;
211 struct rtnl_mdb_entry *entry;
216 proto = ntohs(e->addr.proto);
218 if (proto == ETH_P_IP) {
220 AF_INET, &e->addr.u.ip4,
221 sizeof(e->addr.u.ip4));
222 }
else if (proto == ETH_P_IPV6) {
224 AF_INET6, &e->addr.u.ip6,
225 sizeof(e->addr.u.ip6));
228 AF_LLC, e->addr.u.mac_addr,
229 sizeof(e->addr.u.mac_addr));
234 entry = rtnl_mdb_entry_alloc();
238 mdb->ce_mask |= MDB_ATTR_ENTRIES;
240 entry->ifindex = e->ifindex;
242 entry->state = e->state;
243 entry->proto = ntohs(e->addr.proto);
244 entry->addr = _nl_steal_pointer(&addr);
245 rtnl_mdb_add_entry(mdb, entry);
250 return pp->pp_cb((
struct nl_object *) mdb, pp);
253static int mdb_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
258static void mdb_entry_dump_line(
struct rtnl_mdb_entry *entry,
261 char buf[INET6_ADDRSTRLEN];
263 nl_dump(p,
"port %d ", entry->ifindex);
264 nl_dump(p,
"vid %d ", entry->vid);
265 nl_dump(p,
"proto 0x%04x ", entry->proto);
269static void mdb_dump_line(
struct nl_object *obj,
struct nl_dump_params *p)
271 struct rtnl_mdb *mdb = (
struct rtnl_mdb *) obj;
272 struct rtnl_mdb_entry *_mdb;
274 nl_dump(p,
"dev %d \n", mdb->ifindex);
276 nl_list_for_each_entry(_mdb, &mdb->mdb_entry_list, mdb_list) {
277 p->
dp_ivar = NH_DUMP_FROM_ONELINE;
278 mdb_entry_dump_line(_mdb, p);
282static void mdb_dump_details(
struct nl_object *obj,
struct nl_dump_params *p)
284 mdb_dump_line(obj, p);
287static void mdb_dump_stats(
struct nl_object *obj,
struct nl_dump_params *p)
289 mdb_dump_details(obj, p);
292void rtnl_mdb_put(
struct rtnl_mdb *mdb)
303int rtnl_mdb_alloc_cache(
struct nl_sock *sk,
struct nl_cache **result)
319int rtnl_mdb_alloc_cache_flags(
struct nl_sock *sock,
struct nl_cache **result,
322 struct nl_cache *cache;
346uint32_t rtnl_mdb_get_ifindex(
struct rtnl_mdb *mdb)
351void rtnl_mdb_add_entry(
struct rtnl_mdb *mdb,
struct rtnl_mdb_entry *entry)
353 nl_list_add_tail(&entry->mdb_list, &mdb->mdb_entry_list);
356void rtnl_mdb_foreach_entry(
struct rtnl_mdb *mdb,
357 void (*cb)(
struct rtnl_mdb_entry *,
void *),
360 struct rtnl_mdb_entry *entry;
362 nl_list_for_each_entry(entry, &mdb->mdb_entry_list, mdb_list) {
367int rtnl_mdb_entry_get_ifindex(
struct rtnl_mdb_entry *mdb_entry)
369 return mdb_entry->ifindex;
372int rtnl_mdb_entry_get_vid(
struct rtnl_mdb_entry *mdb_entry)
374 return mdb_entry->vid;
377int rtnl_mdb_entry_get_state(
struct rtnl_mdb_entry *mdb_entry)
379 return mdb_entry->state;
382struct nl_addr *rtnl_mdb_entry_get_addr(
struct rtnl_mdb_entry *mdb_entry)
384 return mdb_entry->addr;
387uint16_t rtnl_mdb_entry_get_proto(
struct rtnl_mdb_entry *mdb_entry)
389 return mdb_entry->proto;
394static struct nl_object_ops mdb_obj_ops = {
395 .oo_name =
"route/mdb",
396 .oo_size =
sizeof(
struct rtnl_mdb),
397 .oo_constructor = mdb_constructor,
403 .oo_clone = mdb_clone,
404 .oo_compare = mdb_compare,
405 .oo_update = mdb_update,
406 .oo_free_data = mdb_free_data,
409struct rtnl_mdb *rtnl_mdb_alloc(
void)
414static struct rtnl_mdb_entry *rtnl_mdb_entry_alloc(
void)
416 struct rtnl_mdb_entry *mdb;
418 mdb = calloc(1,
sizeof(
struct rtnl_mdb_entry));
422 nl_init_list_head(&mdb->mdb_list);
428static void rtnl_mdb_entry_free(
struct rtnl_mdb_entry *mdb_entry)
430 nl_list_del(&mdb_entry->mdb_list);
435static struct nl_af_group mdb_groups[] = {
436 {AF_BRIDGE, RTNLGRP_MDB},
440static struct nl_cache_ops rtnl_mdb_ops = {
441 .co_name =
"route/mdb",
442 .co_hdrsize =
sizeof(
struct br_port_msg),
444 { RTM_NEWMDB, NL_ACT_NEW,
"new"},
445 { RTM_DELMDB, NL_ACT_DEL,
"del"},
446 { RTM_GETMDB, NL_ACT_GET,
"get"},
447 END_OF_MSGTYPES_LIST,
449 .co_protocol = NETLINK_ROUTE,
450 .co_groups = mdb_groups,
451 .co_request_update = mdb_request_update,
452 .co_msg_parser = mdb_msg_parser,
453 .co_obj_ops = &mdb_obj_ops,
456static void __init mdb_init(
void)
461static void __exit mdb_exit(
void)
struct nl_addr * nl_addr_build(int family, const void *buf, size_t size)
Allocate abstract address based on a binary address.
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
struct nlattr * nla_next(const struct nlattr *nla, int *remaining)
Return next attribute in a stream of attributes.
int nla_ok(const struct nlattr *nla, int remaining)
Check if the attribute header and payload can be accessed safely.
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
int nla_len(const struct nlattr *nla)
Return length of the payload .
@ NLA_NESTED
Nested attributes.
int nl_cache_mngt_unregister(struct nl_cache_ops *ops)
Unregister a set of cache operations.
int nl_cache_mngt_register(struct nl_cache_ops *ops)
Register a set of cache operations.
int nl_cache_refill(struct nl_sock *sk, struct nl_cache *cache)
(Re)fill a cache with the contents in the kernel.
void nl_cache_set_flags(struct nl_cache *cache, unsigned int flags)
Set cache flags.
void nl_cache_free(struct nl_cache *cache)
Free a cache.
struct nl_cache * nl_cache_alloc(struct nl_cache_ops *ops)
Allocate new cache.
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.
void * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], int maxtype, const struct nla_policy *policy)
parse attributes of a netlink message
void nl_object_put(struct nl_object *obj)
Release a reference from an object.
struct nl_object * nl_object_alloc(struct nl_object_ops *ops)
Allocate a new object of kind specified by the operations handle.
int nl_rtgen_request(struct nl_sock *sk, int type, int family, int flags)
Send routing netlink request message.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
@ NL_DUMP_STATS
Dump all attributes including statistics.
@ NL_DUMP_LINE
Dump object briefly on one line.
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
int dp_ivar
PRIVATE Owned by the current caller.
Attribute validation policy.
uint16_t type
Type of attribute or NLA_UNSPEC.