8#include <linux/if_bridge.h>
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>
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"
22#define MDB_ATTR_IFINDEX 0x000001
23#define MDB_ATTR_ENTRIES 0x000002
32struct rtnl_mdb_entry {
41static struct rtnl_mdb_entry *rtnl_mdb_entry_alloc(
void);
42static void rtnl_mdb_entry_free(
struct rtnl_mdb_entry *mdb_entry);
44static struct nl_cache_ops rtnl_mdb_ops;
45static struct nl_object_ops mdb_obj_ops;
48static void mdb_constructor(
struct nl_object *obj)
50 struct rtnl_mdb *_mdb = (
struct rtnl_mdb *) obj;
52 nl_init_list_head(&_mdb->mdb_entry_list);
55static void mdb_free_data(
struct nl_object *obj)
57 struct rtnl_mdb *mdb = (
struct rtnl_mdb *)obj;
58 struct rtnl_mdb_entry *mdb_entry;
59 struct rtnl_mdb_entry *mdb_entry_safe;
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);
66static int mdb_entry_equal(
struct rtnl_mdb_entry *a,
struct rtnl_mdb_entry *b)
68 return a->ifindex == b->ifindex
70 && a->proto == b->proto
71 && a->state == b->state
75static uint64_t mdb_compare(
struct nl_object *_a,
struct nl_object *_b,
76 uint64_t attrs,
int flags)
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;
83#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
84 diff |= _DIFF(MDB_ATTR_IFINDEX, a->ifindex != b->ifindex);
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);
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;
97 if (!mdb_entry_equal(a_entry, b_entry)) {
98 diff |= MDB_ATTR_ENTRIES;
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);
108static struct rtnl_mdb_entry *mdb_entry_clone(
struct rtnl_mdb_entry *src)
110 struct rtnl_mdb_entry *dst = rtnl_mdb_entry_alloc();
114 dst->ifindex = src->ifindex;
115 dst->state = src->state;
117 dst->proto = src->proto;
120 if (dst->addr == NULL) {
128static int mdb_clone(
struct nl_object *_dst,
struct nl_object *_src)
130 struct rtnl_mdb *dst = nl_object_priv(_dst);
131 struct rtnl_mdb *src = nl_object_priv(_src);
132 struct rtnl_mdb_entry *entry;
134 nl_init_list_head(&dst->mdb_entry_list);
136 nl_list_for_each_entry(entry, &src->mdb_entry_list, mdb_list) {
137 struct rtnl_mdb_entry *copy = mdb_entry_clone(entry);
142 rtnl_mdb_add_entry(dst, copy);
148static int mdb_update(
struct nl_object *old_obj,
struct nl_object *new_obj)
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;
155 if (new->ifindex != old->ifindex)
156 return -NLE_OPNOTSUPP;
160 nl_list_for_each_entry(entry, &new->mdb_entry_list, mdb_list) {
161 struct rtnl_mdb_entry *copy = mdb_entry_clone(entry);
166 rtnl_mdb_add_entry(old, copy);
170 entry = nl_list_first_entry(&new->mdb_entry_list,
171 struct rtnl_mdb_entry,
173 nl_list_for_each_entry(old_entry, &old->mdb_entry_list, mdb_list) {
174 if ( old_entry->ifindex == entry->ifindex
176 nl_list_del(&old_entry->mdb_list);
186static struct nla_policy mdb_policy[MDBA_MAX + 1] = {
190static struct nla_policy mdb_db_policy[MDBA_MDB_MAX + 1] = {
194static int mdb_msg_parser(
struct nl_cache_ops *ops,
struct sockaddr_nl *who,
195 struct nlmsghdr *nlh,
struct nl_parser_param *pp)
199 struct nlattr *tb[MDBA_MAX + 1];
200 struct br_port_msg *port;
202 struct br_mdb_entry *e;
203 _nl_auto_rtnl_mdb
struct rtnl_mdb *mdb = rtnl_mdb_alloc();
208 err =
nlmsg_parse(nlh,
sizeof(
struct br_port_msg), tb, MDBA_MAX,
213 mdb->ce_msgtype = nlh->nlmsg_type;
216 mdb->ifindex = port->ifindex;
217 mdb->ce_mask |= MDB_ATTR_IFINDEX;
220 struct nlattr *db_attr[MDBA_MDB_MAX+1];
235 _nl_auto_nl_addr
struct nl_addr *addr = NULL;
236 struct rtnl_mdb_entry *entry;
241 proto = ntohs(e->addr.proto);
243 if (proto == ETH_P_IP) {
245 AF_INET, &e->addr.u.ip4,
246 sizeof(e->addr.u.ip4));
247 }
else if (proto == ETH_P_IPV6) {
249 AF_INET6, &e->addr.u.ip6,
250 sizeof(e->addr.u.ip6));
253 AF_LLC, e->addr.u.mac_addr,
254 sizeof(e->addr.u.mac_addr));
259 entry = rtnl_mdb_entry_alloc();
263 mdb->ce_mask |= MDB_ATTR_ENTRIES;
265 entry->ifindex = e->ifindex;
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);
275 return pp->pp_cb((
struct nl_object *) mdb, pp);
278static int mdb_request_update(
struct nl_cache *cache,
struct nl_sock *sk)
283static void mdb_entry_dump_line(
struct rtnl_mdb_entry *entry,
286 char buf[INET6_ADDRSTRLEN];
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);
294static void mdb_dump_line(
struct nl_object *obj,
struct nl_dump_params *p)
296 struct rtnl_mdb *mdb = (
struct rtnl_mdb *) obj;
297 struct rtnl_mdb_entry *_mdb;
299 nl_dump(p,
"dev %d \n", mdb->ifindex);
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);
307static void mdb_dump_details(
struct nl_object *obj,
struct nl_dump_params *p)
309 mdb_dump_line(obj, p);
312static void mdb_dump_stats(
struct nl_object *obj,
struct nl_dump_params *p)
314 mdb_dump_details(obj, p);
317void rtnl_mdb_put(
struct rtnl_mdb *mdb)
328int rtnl_mdb_alloc_cache(
struct nl_sock *sk,
struct nl_cache **result)
344int rtnl_mdb_alloc_cache_flags(
struct nl_sock *sock,
struct nl_cache **result,
347 struct nl_cache *cache;
371uint32_t rtnl_mdb_get_ifindex(
struct rtnl_mdb *mdb)
376void rtnl_mdb_add_entry(
struct rtnl_mdb *mdb,
struct rtnl_mdb_entry *entry)
378 nl_list_add_tail(&entry->mdb_list, &mdb->mdb_entry_list);
381void rtnl_mdb_foreach_entry(
struct rtnl_mdb *mdb,
382 void (*cb)(
struct rtnl_mdb_entry *,
void *),
385 struct rtnl_mdb_entry *entry;
387 nl_list_for_each_entry(entry, &mdb->mdb_entry_list, mdb_list) {
392int rtnl_mdb_entry_get_ifindex(
struct rtnl_mdb_entry *mdb_entry)
394 return mdb_entry->ifindex;
397int rtnl_mdb_entry_get_vid(
struct rtnl_mdb_entry *mdb_entry)
399 return mdb_entry->vid;
402int rtnl_mdb_entry_get_state(
struct rtnl_mdb_entry *mdb_entry)
404 return mdb_entry->state;
407struct nl_addr *rtnl_mdb_entry_get_addr(
struct rtnl_mdb_entry *mdb_entry)
409 return mdb_entry->addr;
412uint16_t rtnl_mdb_entry_get_proto(
struct rtnl_mdb_entry *mdb_entry)
414 return mdb_entry->proto;
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,
428 .oo_clone = mdb_clone,
429 .oo_compare = mdb_compare,
430 .oo_update = mdb_update,
431 .oo_free_data = mdb_free_data,
434struct rtnl_mdb *rtnl_mdb_alloc(
void)
439static struct rtnl_mdb_entry *rtnl_mdb_entry_alloc(
void)
441 struct rtnl_mdb_entry *mdb;
443 mdb = calloc(1,
sizeof(
struct rtnl_mdb_entry));
447 nl_init_list_head(&mdb->mdb_list);
453static void rtnl_mdb_entry_free(
struct rtnl_mdb_entry *mdb_entry)
455 nl_list_del(&mdb_entry->mdb_list);
460static struct nl_af_group mdb_groups[] = {
461 {AF_BRIDGE, RTNLGRP_MDB},
465static struct nl_cache_ops rtnl_mdb_ops = {
466 .co_name =
"route/mdb",
467 .co_hdrsize =
sizeof(
struct br_port_msg),
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,
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,
481static void _nl_init mdb_init(
void)
486static void _nl_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.