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
16 static struct rtnl_mdb_entry *rtnl_mdb_entry_alloc(
void);
18 static struct nl_cache_ops rtnl_mdb_ops;
19 static struct nl_object_ops mdb_obj_ops;
22 static void mdb_constructor(
struct nl_object *obj)
24 struct rtnl_mdb *_mdb = (
struct rtnl_mdb *) obj;
26 nl_init_list_head(&_mdb->mdb_entry_list);
29 static void mdb_free_data(
struct nl_object *obj)
31 struct rtnl_mdb *mdb = (
struct rtnl_mdb *) obj;
32 struct rtnl_mdb_entry *mdb_entry;
33 struct rtnl_mdb_entry *mdb_entry_safe;
35 nl_list_for_each_entry_safe(mdb_entry, mdb_entry_safe, &mdb->mdb_entry_list, mdb_list) {
36 nl_list_del(&mdb_entry->mdb_list);
42 static int mdb_entry_equal(
struct rtnl_mdb_entry *a,
struct rtnl_mdb_entry *b)
44 return a->ifindex == b->ifindex
46 && a->proto == b->proto
47 && a->state == b->state
51 static uint64_t mdb_compare(
struct nl_object *_a,
struct nl_object *_b,
52 uint64_t attrs,
int flags)
54 struct rtnl_mdb *a = (
struct rtnl_mdb *) _a;
55 struct rtnl_mdb *b = (
struct rtnl_mdb *) _b;
56 struct rtnl_mdb_entry *a_entry, *b_entry;
59 #define MDB_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MDB_ATTR_##ATTR, a, b, EXPR)
60 diff |= MDB_DIFF(IFINDEX, a->ifindex != b->ifindex);
63 a_entry = nl_list_entry(a->mdb_entry_list.next,
struct rtnl_mdb_entry, mdb_list);
64 b_entry = nl_list_entry(b->mdb_entry_list.next,
struct rtnl_mdb_entry, mdb_list);
66 if ( &a_entry->mdb_list == &a->mdb_entry_list
67 || &b_entry->mdb_list == &b->mdb_entry_list) {
68 if ( &a_entry->mdb_list != &a->mdb_entry_list
69 || &b_entry->mdb_list != &b->mdb_entry_list)
70 diff |= MDB_ATTR_ENTRIES;
73 if (!mdb_entry_equal(a_entry, b_entry)) {
74 diff |= MDB_ATTR_ENTRIES;
77 a_entry = nl_list_entry(a_entry->mdb_list.next,
struct rtnl_mdb_entry, mdb_list);
78 b_entry = nl_list_entry(b_entry->mdb_list.next,
struct rtnl_mdb_entry, mdb_list);
84 static struct rtnl_mdb_entry *mdb_entry_clone(
struct rtnl_mdb_entry *src)
86 struct rtnl_mdb_entry *dst = rtnl_mdb_entry_alloc();
90 dst->ifindex = src->ifindex;
91 dst->state = src->state;
93 dst->proto = src->proto;
96 if (dst->addr == NULL) {
104 static int mdb_clone(
struct nl_object *_dst,
struct nl_object *_src)
106 struct rtnl_mdb *dst = nl_object_priv(_dst);
107 struct rtnl_mdb *src = nl_object_priv(_src);
108 struct rtnl_mdb_entry *entry;
110 nl_init_list_head(&dst->mdb_entry_list);
112 nl_list_for_each_entry(entry, &src->mdb_entry_list, mdb_list) {
113 struct rtnl_mdb_entry *copy = mdb_entry_clone(entry);
118 rtnl_mdb_add_entry(dst, copy);
124 static int mdb_update(
struct nl_object *old_obj,
struct nl_object *new_obj)
126 struct rtnl_mdb *old = (
struct rtnl_mdb *) old_obj;
127 struct rtnl_mdb *
new = (
struct rtnl_mdb *) new_obj;
128 struct rtnl_mdb_entry *entry, *old_entry;
129 int action = new_obj->ce_msgtype;
131 if (new->ifindex != old->ifindex)
132 return -NLE_OPNOTSUPP;
136 nl_list_for_each_entry(entry, &new->mdb_entry_list, mdb_list) {
137 struct rtnl_mdb_entry *copy = mdb_entry_clone(entry);
142 rtnl_mdb_add_entry(old, copy);
146 entry = nl_list_first_entry(&new->mdb_entry_list,
147 struct rtnl_mdb_entry,
149 nl_list_for_each_entry(old_entry, &old->mdb_entry_list, mdb_list) {
150 if ( old_entry->ifindex == entry->ifindex
152 nl_list_del(&old_entry->mdb_list);
162 static struct nla_policy mdb_policy[MDBA_MAX + 1] = {
166 static struct nla_policy mdb_db_policy[MDBA_MDB_MAX + 1] = {
170 static int mdb_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
171 struct nlmsghdr *nlh,
struct nl_parser_param *pp)
175 struct nlattr *tb[MDBA_MAX + 1];
176 struct br_port_msg *port;
178 struct br_mdb_entry *e;
179 struct rtnl_mdb *mdb = rtnl_mdb_alloc();
184 err =
nlmsg_parse(nlh,
sizeof(
struct br_port_msg), tb, MDBA_MAX,
189 mdb->ce_msgtype = nlh->nlmsg_type;
192 mdb->ifindex = port->ifindex;
193 mdb->ce_mask |= MDB_ATTR_IFINDEX;
196 struct nlattr *db_attr[MDBA_MDB_MAX];
209 struct rtnl_mdb_entry *entry = rtnl_mdb_entry_alloc();
217 mdb->ce_mask |= MDB_ATTR_ENTRIES;
219 entry->ifindex = e->ifindex;
223 entry->state = e->state;
225 entry->proto = ntohs(e->addr.proto);
227 if (entry->proto == ETH_P_IP) {
230 sizeof(e->addr.u.ip4));
231 }
else if (entry->proto == ETH_P_IPV6) {
234 sizeof(e->addr.u.ip6));
238 sizeof(e->addr.u.mac_addr));
244 rtnl_mdb_add_entry(mdb, entry);
249 err = pp->pp_cb((
struct nl_object *) mdb, pp);
256 static int mdb_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
261 static void mdb_entry_dump_line(
struct rtnl_mdb_entry *entry,
264 char buf[INET6_ADDRSTRLEN];
266 nl_dump(p,
"port %d ", entry->ifindex);
267 nl_dump(p,
"vid %d ", entry->vid);
268 nl_dump(p,
"proto 0x%04x ", entry->proto);
272 static void mdb_dump_line(
struct nl_object *obj,
struct nl_dump_params *p)
274 struct rtnl_mdb *mdb = (
struct rtnl_mdb *) obj;
275 struct rtnl_mdb_entry *_mdb;
277 nl_dump(p,
"dev %d \n", mdb->ifindex);
279 nl_list_for_each_entry(_mdb, &mdb->mdb_entry_list, mdb_list) {
280 p->
dp_ivar = NH_DUMP_FROM_ONELINE;
281 mdb_entry_dump_line(_mdb, p);
285 static void mdb_dump_details(
struct nl_object *obj,
struct nl_dump_params *p)
287 mdb_dump_line(obj, p);
290 static void mdb_dump_stats(
struct nl_object *obj,
struct nl_dump_params *p)
292 mdb_dump_details(obj, p);
295 void rtnl_mdb_put(
struct rtnl_mdb *mdb)
306 int rtnl_mdb_alloc_cache(
struct nl_sock *sk,
struct nl_cache **result)
322 int rtnl_mdb_alloc_cache_flags(
struct nl_sock *sock,
struct nl_cache **result,
325 struct nl_cache *cache;
349 uint32_t rtnl_mdb_get_ifindex(
struct rtnl_mdb *mdb)
354 void rtnl_mdb_add_entry(
struct rtnl_mdb *mdb,
struct rtnl_mdb_entry *entry)
356 nl_list_add_tail(&entry->mdb_list, &mdb->mdb_entry_list);
359 void rtnl_mdb_foreach_entry(
struct rtnl_mdb *mdb,
360 void (*cb)(
struct rtnl_mdb_entry *,
void *),
363 struct rtnl_mdb_entry *entry;
365 nl_list_for_each_entry(entry, &mdb->mdb_entry_list, mdb_list) {
370 int rtnl_mdb_entry_get_ifindex(
struct rtnl_mdb_entry *mdb_entry)
372 return mdb_entry->ifindex;
375 int rtnl_mdb_entry_get_vid(
struct rtnl_mdb_entry *mdb_entry)
377 return mdb_entry->vid;
380 int rtnl_mdb_entry_get_state(
struct rtnl_mdb_entry *mdb_entry)
382 return mdb_entry->state;
385 struct nl_addr *rtnl_mdb_entry_get_addr(
struct rtnl_mdb_entry *mdb_entry)
387 return mdb_entry->addr;
390 uint16_t rtnl_mdb_entry_get_proto(
struct rtnl_mdb_entry *mdb_entry)
392 return mdb_entry->proto;
397 static struct nl_object_ops mdb_obj_ops = {
398 .oo_name =
"route/mdb",
399 .oo_size =
sizeof(
struct rtnl_mdb),
400 .oo_constructor = mdb_constructor,
406 .oo_clone = mdb_clone,
407 .oo_compare = mdb_compare,
408 .oo_update = mdb_update,
409 .oo_free_data = mdb_free_data,
412 struct rtnl_mdb *rtnl_mdb_alloc(
void)
417 static struct rtnl_mdb_entry *rtnl_mdb_entry_alloc(
void)
419 struct rtnl_mdb_entry *mdb;
421 mdb = calloc(1,
sizeof(
struct rtnl_mdb_entry));
425 nl_init_list_head(&mdb->mdb_list);
431 static struct nl_af_group mdb_groups[] = {
432 {AF_BRIDGE, RTNLGRP_MDB},
436 static struct nl_cache_ops rtnl_mdb_ops = {
437 .co_name =
"route/mdb",
438 .co_hdrsize =
sizeof(
struct br_port_msg),
440 { RTM_NEWMDB, NL_ACT_NEW,
"new"},
441 { RTM_DELMDB, NL_ACT_DEL,
"del"},
442 { RTM_GETMDB, NL_ACT_GET,
"get"},
443 END_OF_MSGTYPES_LIST,
445 .co_protocol = NETLINK_ROUTE,
446 .co_groups = mdb_groups,
447 .co_request_update = mdb_request_update,
448 .co_msg_parser = mdb_msg_parser,
449 .co_obj_ops = &mdb_obj_ops,
452 static void __init mdb_init(
void)
457 static void __exit mdb_exit(
void)
char * nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
Convert abstract address object to character string.
int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
Compare abstract addresses.
struct nl_addr * nl_addr_build(int family, const void *buf, size_t size)
Allocate abstract address based on a binary address.
struct nl_addr * nl_addr_clone(const struct nl_addr *addr)
Clone existing abstract address object.
void nl_addr_put(struct nl_addr *addr)
Decrease the reference counter of an abstract address.
int nla_ok(const struct nlattr *nla, int remaining)
Check if the attribute header and payload can be accessed safely.
struct nlattr * nla_next(const struct nlattr *nla, int *remaining)
Return next attribute in a stream of attributes.
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 .
void * nla_data(const struct nlattr *nla)
Return pointer to the payload section.
@ 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.
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.
struct nl_cache * nl_cache_alloc(struct nl_cache_ops *ops)
Allocate new cache.
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 * nlmsg_data(const struct nlmsghdr *nlh)
Return pointer to message payload.
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.