diff options
author | Cong Wang <amwang@redhat.com> | 2012-12-11 17:23:07 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-12-12 13:02:30 -0500 |
commit | 37a393bc4932d7bac360f40064aaafc01ab44901 (patch) | |
tree | 61a0a7cd1ab9db418558dbc44d4455868b7220cb /net/bridge/br_mdb.c | |
parent | fd0ea7dbfae16015e72c4bbc6b1b43fffc3b914f (diff) |
bridge: notify mdb changes via netlink
As Stephen mentioned, we need to monitor the mdb
changes in user-space, so add notifications via netlink too.
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: Stephen Hemminger <shemminger@vyatta.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Thomas Graf <tgraf@suug.ch>
Signed-off-by: Cong Wang <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/bridge/br_mdb.c')
-rw-r--r-- | net/bridge/br_mdb.c | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index ccc43a9bff80..a8cfbf5f3c68 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c | |||
@@ -155,6 +155,86 @@ out: | |||
155 | return skb->len; | 155 | return skb->len; |
156 | } | 156 | } |
157 | 157 | ||
158 | static int nlmsg_populate_mdb_fill(struct sk_buff *skb, | ||
159 | struct net_device *dev, | ||
160 | struct br_mdb_entry *entry, u32 pid, | ||
161 | u32 seq, int type, unsigned int flags) | ||
162 | { | ||
163 | struct nlmsghdr *nlh; | ||
164 | struct br_port_msg *bpm; | ||
165 | struct nlattr *nest, *nest2; | ||
166 | |||
167 | nlh = nlmsg_put(skb, pid, seq, type, sizeof(*bpm), NLM_F_MULTI); | ||
168 | if (!nlh) | ||
169 | return -EMSGSIZE; | ||
170 | |||
171 | bpm = nlmsg_data(nlh); | ||
172 | bpm->family = AF_BRIDGE; | ||
173 | bpm->ifindex = dev->ifindex; | ||
174 | nest = nla_nest_start(skb, MDBA_MDB); | ||
175 | if (nest == NULL) | ||
176 | goto cancel; | ||
177 | nest2 = nla_nest_start(skb, MDBA_MDB_ENTRY); | ||
178 | if (nest2 == NULL) | ||
179 | goto end; | ||
180 | |||
181 | if (nla_put(skb, MDBA_MDB_ENTRY_INFO, sizeof(*entry), entry)) | ||
182 | goto end; | ||
183 | |||
184 | nla_nest_end(skb, nest2); | ||
185 | nla_nest_end(skb, nest); | ||
186 | return nlmsg_end(skb, nlh); | ||
187 | |||
188 | end: | ||
189 | nla_nest_end(skb, nest); | ||
190 | cancel: | ||
191 | nlmsg_cancel(skb, nlh); | ||
192 | return -EMSGSIZE; | ||
193 | } | ||
194 | |||
195 | static inline size_t rtnl_mdb_nlmsg_size(void) | ||
196 | { | ||
197 | return NLMSG_ALIGN(sizeof(struct br_port_msg)) | ||
198 | + nla_total_size(sizeof(struct br_mdb_entry)); | ||
199 | } | ||
200 | |||
201 | static void __br_mdb_notify(struct net_device *dev, struct br_mdb_entry *entry, | ||
202 | int type) | ||
203 | { | ||
204 | struct net *net = dev_net(dev); | ||
205 | struct sk_buff *skb; | ||
206 | int err = -ENOBUFS; | ||
207 | |||
208 | skb = nlmsg_new(rtnl_mdb_nlmsg_size(), GFP_ATOMIC); | ||
209 | if (!skb) | ||
210 | goto errout; | ||
211 | |||
212 | err = nlmsg_populate_mdb_fill(skb, dev, entry, 0, 0, type, NTF_SELF); | ||
213 | if (err < 0) { | ||
214 | kfree_skb(skb); | ||
215 | goto errout; | ||
216 | } | ||
217 | |||
218 | rtnl_notify(skb, net, 0, RTNLGRP_MDB, NULL, GFP_ATOMIC); | ||
219 | return; | ||
220 | errout: | ||
221 | rtnl_set_sk_err(net, RTNLGRP_MDB, err); | ||
222 | } | ||
223 | |||
224 | void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port, | ||
225 | struct br_ip *group, int type) | ||
226 | { | ||
227 | struct br_mdb_entry entry; | ||
228 | |||
229 | entry.ifindex = port->dev->ifindex; | ||
230 | entry.addr.proto = group->proto; | ||
231 | entry.addr.u.ip4 = group->u.ip4; | ||
232 | #if IS_ENABLED(CONFIG_IPV6) | ||
233 | entry.addr.u.ip6 = group->u.ip6; | ||
234 | #endif | ||
235 | __br_mdb_notify(dev, &entry, type); | ||
236 | } | ||
237 | |||
158 | void br_mdb_init(void) | 238 | void br_mdb_init(void) |
159 | { | 239 | { |
160 | rtnl_register(PF_BRIDGE, RTM_GETMDB, NULL, br_mdb_dump, NULL); | 240 | rtnl_register(PF_BRIDGE, RTM_GETMDB, NULL, br_mdb_dump, NULL); |