Add support for filtering neighbor dumps by master device by adding the NDA_MASTER attribute to the dump request. A new netlink flag, NLM_F_DUMP_FILTERED, is added to indicate the kernel supports the request and output is filtered as requested.
Unified · Split
| @@ -54,6 +54,7 @@ struct nlmsghdr { · 53 unmodified lines | ||
| 54 | 54 | #define NLM_F_ACK 4 /* Reply with ack, with zero or error code */ |
| 55 | 55 | #define NLM_F_ECHO 8 /* Echo this request */ |
| 56 | 56 | #define NLM_F_DUMP_INTR 16 /* Dump was inconsistent due to sequence change */ |
| 57 | +#define NLM_F_DUMP_FILTERED 32 /* Dump was filtered as requested */ | |
| 57 | 58 | |
| 58 | 59 | /* Modifiers to GET request */ |
| 59 | 60 | #define NLM_F_ROOT 0x100 /* specify tree root */ |
| @@ -2235,14 +2235,42 @@ static void neigh_update_notify(struct neighbour *neigh) · 2234 unmodified lines | ||
| 2235 | 2235 | __neigh_notify(neigh, RTM_NEWNEIGH, 0); |
| 2236 | 2236 | } |
| 2237 | 2237 | |
| 2238 | +static bool neigh_master_filtered(struct net_device *dev, int master_idx) | |
| 2239 | +{ | |
| 2240 | + struct net_device *master; | |
| 2241 | + | |
| 2242 | + if (!master_idx) | |
| 2243 | + return false; | |
| 2244 | + | |
| 2245 | + master = netdev_master_upper_dev_get(dev); | |
| 2246 | + if (!master || master->ifindex != master_idx) | |
| 2247 | + return true; | |
| 2248 | + | |
| 2249 | + return false; | |
| 2250 | +} | |
| 2251 | + | |
| 2238 | 2252 | static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, |
| 2239 | 2253 | struct netlink_callback *cb) |
| 2240 | 2254 | { |
| 2241 | 2255 | struct net *net = sock_net(skb->sk); |
| 2256 | + const struct nlmsghdr *nlh = cb->nlh; | |
| 2257 | + struct nlattr *tb[NDA_MAX + 1]; | |
| 2242 | 2258 | struct neighbour *n; |
| 2243 | 2259 | int rc, h, s_h = cb->args[1]; |
| 2244 | 2260 | int idx, s_idx = idx = cb->args[2]; |
| 2245 | 2261 | struct neigh_hash_table *nht; |
| 2262 | + int filter_master_idx = 0; | |
| 2263 | + unsigned int flags = NLM_F_MULTI; | |
| 2264 | + int err; | |
| 2265 | + | |
| 2266 | + err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL); | |
| 2267 | + if (!err) { | |
| 2268 | + if (tb[NDA_MASTER]) | |
| 2269 | + filter_master_idx = nla_get_u32(tb[NDA_MASTER]); | |
| 2270 | + | |
| 2271 | + if (filter_master_idx) | |
| 2272 | + flags |= NLM_F_DUMP_FILTERED; | |
| 2273 | + } | |
| 2246 | 2274 | |
| 2247 | 2275 | rcu_read_lock_bh(); |
| 2248 | 2276 | nht = rcu_dereference_bh(tbl->nht); |
| @@ -2255,12 +2283,14 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, · 6 unmodified lines | ||
| 2255 | 2283 | n = rcu_dereference_bh(n->next)) { |
| 2256 | 2284 | if (!net_eq(dev_net(n->dev), net)) |
| 2257 | 2285 | continue; |
| 2286 | + if (neigh_master_filtered(n->dev, filter_master_idx)) | |
| 2287 | + continue; | |
| 2258 | 2288 | if (idx < s_idx) |
| 2259 | 2289 | goto next; |
| 2260 | 2290 | if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, |
| 2261 | 2291 | cb->nlh->nlmsg_seq, |
| 2262 | 2292 | RTM_NEWNEIGH, |
| 2263 | − NLM_F_MULTI) < 0) { | |
| 2293 | + flags) < 0) { | |
| 2264 | 2294 | rc = -1; |
| 2265 | 2295 | goto out; |
| 2266 | 2296 | } |