diff options
author | John Fastabend <john.r.fastabend@intel.com> | 2012-04-15 02:44:14 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-04-15 13:06:04 -0400 |
commit | 3ff661c38c8492a2859e39e0ea1e3b6d30e89bf5 (patch) | |
tree | b9bbd41a8fd1764cc49e8a2bb7c777328800eaa8 /net | |
parent | d83b060360485454fcd6870340ec01d6f96f2295 (diff) |
net: rtnetlink notify events for FDB NTF_SELF adds and deletes
It is useful to be able to monitor for FDB events in user space.
This patch adds support to generate netlink events when a change
is made to a device supporting the FDB ops.
This brings embedded switches inline with the SW net/bridge which
triggers events on FDB updates as well.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/core/rtnetlink.c | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index e8488c7b092c..b442d35bbc8b 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -2011,6 +2011,33 @@ nla_put_failure: | |||
2011 | return -EMSGSIZE; | 2011 | return -EMSGSIZE; |
2012 | } | 2012 | } |
2013 | 2013 | ||
2014 | static inline size_t rtnl_fdb_nlmsg_size(void) | ||
2015 | { | ||
2016 | return NLMSG_ALIGN(sizeof(struct ndmsg)) + nla_total_size(ETH_ALEN); | ||
2017 | } | ||
2018 | |||
2019 | static void rtnl_fdb_notify(struct net_device *dev, u8 *addr, int type) | ||
2020 | { | ||
2021 | struct net *net = dev_net(dev); | ||
2022 | struct sk_buff *skb; | ||
2023 | int err = -ENOBUFS; | ||
2024 | |||
2025 | skb = nlmsg_new(rtnl_fdb_nlmsg_size(), GFP_ATOMIC); | ||
2026 | if (!skb) | ||
2027 | goto errout; | ||
2028 | |||
2029 | err = nlmsg_populate_fdb_fill(skb, dev, addr, 0, 0, type, NTF_SELF); | ||
2030 | if (err < 0) { | ||
2031 | kfree_skb(skb); | ||
2032 | goto errout; | ||
2033 | } | ||
2034 | |||
2035 | rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); | ||
2036 | return; | ||
2037 | errout: | ||
2038 | rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); | ||
2039 | } | ||
2040 | |||
2014 | static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | 2041 | static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) |
2015 | { | 2042 | { |
2016 | struct net *net = sock_net(skb->sk); | 2043 | struct net *net = sock_net(skb->sk); |
@@ -2067,8 +2094,10 @@ static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2067 | err = dev->netdev_ops->ndo_fdb_add(ndm, dev, addr, | 2094 | err = dev->netdev_ops->ndo_fdb_add(ndm, dev, addr, |
2068 | nlh->nlmsg_flags); | 2095 | nlh->nlmsg_flags); |
2069 | 2096 | ||
2070 | if (!err) | 2097 | if (!err) { |
2098 | rtnl_fdb_notify(dev, addr, RTM_NEWNEIGH); | ||
2071 | ndm->ndm_flags &= ~NTF_SELF; | 2099 | ndm->ndm_flags &= ~NTF_SELF; |
2100 | } | ||
2072 | } | 2101 | } |
2073 | out: | 2102 | out: |
2074 | return err; | 2103 | return err; |
@@ -2125,8 +2154,10 @@ static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) | |||
2125 | if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) { | 2154 | if ((ndm->ndm_flags & NTF_SELF) && dev->netdev_ops->ndo_fdb_del) { |
2126 | err = dev->netdev_ops->ndo_fdb_del(ndm, dev, addr); | 2155 | err = dev->netdev_ops->ndo_fdb_del(ndm, dev, addr); |
2127 | 2156 | ||
2128 | if (!err) | 2157 | if (!err) { |
2158 | rtnl_fdb_notify(dev, addr, RTM_DELNEIGH); | ||
2129 | ndm->ndm_flags &= ~NTF_SELF; | 2159 | ndm->ndm_flags &= ~NTF_SELF; |
2160 | } | ||
2130 | } | 2161 | } |
2131 | out: | 2162 | out: |
2132 | return err; | 2163 | return err; |