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 | #define NLM_F_ACK 4 /* Reply with ack, with zero or error code */ | 54 | #define NLM_F_ACK 4 /* Reply with ack, with zero or error code */ |
| 55 | #define NLM_F_ECHO 8 /* Echo this request */ | 55 | #define NLM_F_ECHO 8 /* Echo this request */ |
| 56 | #define NLM_F_DUMP_INTR 16 /* Dump was inconsistent due to sequence change */ | 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 | /* Modifiers to GET request */ | 59 | /* Modifiers to GET request */ |
| 59 | #define NLM_F_ROOT 0x100 /* specify tree root */ | 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 | __neigh_notify(neigh, RTM_NEWNEIGH, 0); | 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 | static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, | 2252 | static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, |
| 2239 | struct netlink_callback *cb) | 2253 | struct netlink_callback *cb) |
| 2240 | { | 2254 | { |
| 2241 | struct net *net = sock_net(skb->sk); | 2255 | struct net *net = sock_net(skb->sk); |
| 2256 | const struct nlmsghdr *nlh = cb->nlh; | ||
| 2257 | struct nlattr *tb[NDA_MAX + 1]; | ||
| 2242 | struct neighbour *n; | 2258 | struct neighbour *n; |
| 2243 | int rc, h, s_h = cb->args[1]; | 2259 | int rc, h, s_h = cb->args[1]; |
| 2244 | int idx, s_idx = idx = cb->args[2]; | 2260 | int idx, s_idx = idx = cb->args[2]; |
| 2245 | struct neigh_hash_table *nht; | 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 | rcu_read_lock_bh(); | 2275 | rcu_read_lock_bh(); |
| 2248 | nht = rcu_dereference_bh(tbl->nht); | 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 | n = rcu_dereference_bh(n->next)) { | 2283 | n = rcu_dereference_bh(n->next)) { |
| 2256 | if (!net_eq(dev_net(n->dev), net)) | 2284 | if (!net_eq(dev_net(n->dev), net)) |
| 2257 | continue; | 2285 | continue; |
| 2286 | if (neigh_master_filtered(n->dev, filter_master_idx)) | ||
| 2287 | continue; | ||
| 2258 | if (idx < s_idx) | 2288 | if (idx < s_idx) |
| 2259 | goto next; | 2289 | goto next; |
| 2260 | if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, | 2290 | if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, |
| 2261 | cb->nlh->nlmsg_seq, | 2291 | cb->nlh->nlmsg_seq, |
| 2262 | RTM_NEWNEIGH, | 2292 | RTM_NEWNEIGH, |
| 2263 | NLM_F_MULTI) < 0) { | 2293 | flags) < 0) { |
| 2264 | rc = -1; | 2294 | rc = -1; |
| 2265 | goto out; | 2295 | goto out; |
| 2266 | } | 2296 | } |