summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoopa Prabhu <roopa@cumulusnetworks.com>2018-12-19 15:51:38 -0500
committerDavid S. Miller <davem@davemloft.net>2018-12-19 16:37:34 -0500
commit82cbb5c631a07b3aa6df6eab644d55da9de5a645 (patch)
treef071d0fa16682ef217525ff8236c3713b884934d
parent4ab0edecaf1d9a4acb5bddc4a869b0f7efda634a (diff)
neighbour: register rtnl doit handler
this patch registers neigh doit handler. The doit handler returns a neigh entry given dst and dev. This is similar to route and fdb doit (get) handlers. Also moves nda_policy declaration from rtnetlink.c to neighbour.c Signed-off-by: Roopa Prabhu <roopa@cumulusnetworks.com> Reviewed-by: David Ahern <dsa@cumulusnetworks.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/neighbour.h1
-rw-r--r--net/core/neighbour.c204
-rw-r--r--net/core/rtnetlink.c12
3 files changed, 194 insertions, 23 deletions
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 66221f1991c0..7c1ab9edba03 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -255,6 +255,7 @@ static inline void *neighbour_priv(const struct neighbour *n)
255#define NEIGH_UPDATE_F_ISROUTER 0x40000000 255#define NEIGH_UPDATE_F_ISROUTER 0x40000000
256#define NEIGH_UPDATE_F_ADMIN 0x80000000 256#define NEIGH_UPDATE_F_ADMIN 0x80000000
257 257
258extern const struct nla_policy nda_policy[];
258 259
259static inline bool neigh_key_eq16(const struct neighbour *n, const void *pkey) 260static inline bool neigh_key_eq16(const struct neighbour *n, const void *pkey)
260{ 261{
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index fb4372cb1de1..43687c9abe1d 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1751,6 +1751,18 @@ static struct neigh_table *neigh_find_table(int family)
1751 return tbl; 1751 return tbl;
1752} 1752}
1753 1753
1754const struct nla_policy nda_policy[NDA_MAX+1] = {
1755 [NDA_DST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1756 [NDA_LLADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
1757 [NDA_CACHEINFO] = { .len = sizeof(struct nda_cacheinfo) },
1758 [NDA_PROBES] = { .type = NLA_U32 },
1759 [NDA_VLAN] = { .type = NLA_U16 },
1760 [NDA_PORT] = { .type = NLA_U16 },
1761 [NDA_VNI] = { .type = NLA_U32 },
1762 [NDA_IFINDEX] = { .type = NLA_U32 },
1763 [NDA_MASTER] = { .type = NLA_U32 },
1764};
1765
1754static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, 1766static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh,
1755 struct netlink_ext_ack *extack) 1767 struct netlink_ext_ack *extack)
1756{ 1768{
@@ -2711,6 +2723,186 @@ static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
2711 return skb->len; 2723 return skb->len;
2712} 2724}
2713 2725
2726static int neigh_valid_get_req(const struct nlmsghdr *nlh,
2727 struct neigh_table **tbl,
2728 void **dst, int *dev_idx, u8 *ndm_flags,
2729 struct netlink_ext_ack *extack)
2730{
2731 struct nlattr *tb[NDA_MAX + 1];
2732 struct ndmsg *ndm;
2733 int err, i;
2734
2735 if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ndm))) {
2736 NL_SET_ERR_MSG(extack, "Invalid header for neighbor get request");
2737 return -EINVAL;
2738 }
2739
2740 ndm = nlmsg_data(nlh);
2741 if (ndm->ndm_pad1 || ndm->ndm_pad2 || ndm->ndm_state ||
2742 ndm->ndm_type) {
2743 NL_SET_ERR_MSG(extack, "Invalid values in header for neighbor get request");
2744 return -EINVAL;
2745 }
2746
2747 if (ndm->ndm_flags & ~NTF_PROXY) {
2748 NL_SET_ERR_MSG(extack, "Invalid flags in header for neighbor get request");
2749 return -EINVAL;
2750 }
2751
2752 err = nlmsg_parse_strict(nlh, sizeof(struct ndmsg), tb, NDA_MAX,
2753 nda_policy, extack);
2754 if (err < 0)
2755 return err;
2756
2757 *ndm_flags = ndm->ndm_flags;
2758 *dev_idx = ndm->ndm_ifindex;
2759 *tbl = neigh_find_table(ndm->ndm_family);
2760 if (*tbl == NULL) {
2761 NL_SET_ERR_MSG(extack, "Unsupported family in header for neighbor get request");
2762 return -EAFNOSUPPORT;
2763 }
2764
2765 for (i = 0; i <= NDA_MAX; ++i) {
2766 if (!tb[i])
2767 continue;
2768
2769 switch (i) {
2770 case NDA_DST:
2771 if (nla_len(tb[i]) != (int)(*tbl)->key_len) {
2772 NL_SET_ERR_MSG(extack, "Invalid network address in neighbor get request");
2773 return -EINVAL;
2774 }
2775 *dst = nla_data(tb[i]);
2776 break;
2777 default:
2778 NL_SET_ERR_MSG(extack, "Unsupported attribute in neighbor get request");
2779 return -EINVAL;
2780 }
2781 }
2782
2783 return 0;
2784}
2785
2786static inline size_t neigh_nlmsg_size(void)
2787{
2788 return NLMSG_ALIGN(sizeof(struct ndmsg))
2789 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
2790 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
2791 + nla_total_size(sizeof(struct nda_cacheinfo))
2792 + nla_total_size(4) /* NDA_PROBES */
2793 + nla_total_size(1); /* NDA_PROTOCOL */
2794}
2795
2796static int neigh_get_reply(struct net *net, struct neighbour *neigh,
2797 u32 pid, u32 seq)
2798{
2799 struct sk_buff *skb;
2800 int err = 0;
2801
2802 skb = nlmsg_new(neigh_nlmsg_size(), GFP_KERNEL);
2803 if (!skb)
2804 return -ENOBUFS;
2805
2806 err = neigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0);
2807 if (err) {
2808 kfree_skb(skb);
2809 goto errout;
2810 }
2811
2812 err = rtnl_unicast(skb, net, pid);
2813errout:
2814 return err;
2815}
2816
2817static inline size_t pneigh_nlmsg_size(void)
2818{
2819 return NLMSG_ALIGN(sizeof(struct ndmsg))
2820 + nla_total_size(MAX_ADDR_LEN); /* NDA_DST */
2821 + nla_total_size(1); /* NDA_PROTOCOL */
2822}
2823
2824static int pneigh_get_reply(struct net *net, struct pneigh_entry *neigh,
2825 u32 pid, u32 seq, struct neigh_table *tbl)
2826{
2827 struct sk_buff *skb;
2828 int err = 0;
2829
2830 skb = nlmsg_new(pneigh_nlmsg_size(), GFP_KERNEL);
2831 if (!skb)
2832 return -ENOBUFS;
2833
2834 err = pneigh_fill_info(skb, neigh, pid, seq, RTM_NEWNEIGH, 0, tbl);
2835 if (err) {
2836 kfree_skb(skb);
2837 goto errout;
2838 }
2839
2840 err = rtnl_unicast(skb, net, pid);
2841errout:
2842 return err;
2843}
2844
2845static int neigh_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
2846 struct netlink_ext_ack *extack)
2847{
2848 struct net *net = sock_net(in_skb->sk);
2849 struct net_device *dev = NULL;
2850 struct neigh_table *tbl = NULL;
2851 struct neighbour *neigh;
2852 void *dst = NULL;
2853 u8 ndm_flags = 0;
2854 int dev_idx = 0;
2855 int err;
2856
2857 err = neigh_valid_get_req(nlh, &tbl, &dst, &dev_idx, &ndm_flags,
2858 extack);
2859 if (err < 0)
2860 return err;
2861
2862 if (dev_idx) {
2863 dev = __dev_get_by_index(net, dev_idx);
2864 if (!dev) {
2865 NL_SET_ERR_MSG(extack, "Unknown device ifindex");
2866 return -ENODEV;
2867 }
2868 }
2869
2870 if (!dst) {
2871 NL_SET_ERR_MSG(extack, "Network address not specified");
2872 return -EINVAL;
2873 }
2874
2875 if (ndm_flags & NTF_PROXY) {
2876 struct pneigh_entry *pn;
2877
2878 pn = pneigh_lookup(tbl, net, dst, dev, 0);
2879 if (!pn) {
2880 NL_SET_ERR_MSG(extack, "Proxy neighbour entry not found");
2881 return -ENOENT;
2882 }
2883 return pneigh_get_reply(net, pn, NETLINK_CB(in_skb).portid,
2884 nlh->nlmsg_seq, tbl);
2885 }
2886
2887 if (!dev) {
2888 NL_SET_ERR_MSG(extack, "No device specified");
2889 return -EINVAL;
2890 }
2891
2892 neigh = neigh_lookup(tbl, dst, dev);
2893 if (!neigh) {
2894 NL_SET_ERR_MSG(extack, "Neighbour entry not found");
2895 return -ENOENT;
2896 }
2897
2898 err = neigh_get_reply(net, neigh, NETLINK_CB(in_skb).portid,
2899 nlh->nlmsg_seq);
2900
2901 neigh_release(neigh);
2902
2903 return err;
2904}
2905
2714void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie) 2906void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie)
2715{ 2907{
2716 int chain; 2908 int chain;
@@ -3118,16 +3310,6 @@ static const struct seq_operations neigh_stat_seq_ops = {
3118}; 3310};
3119#endif /* CONFIG_PROC_FS */ 3311#endif /* CONFIG_PROC_FS */
3120 3312
3121static inline size_t neigh_nlmsg_size(void)
3122{
3123 return NLMSG_ALIGN(sizeof(struct ndmsg))
3124 + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */
3125 + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */
3126 + nla_total_size(sizeof(struct nda_cacheinfo))
3127 + nla_total_size(4) /* NDA_PROBES */
3128 + nla_total_size(1); /* NDA_PROTOCOL */
3129}
3130
3131static void __neigh_notify(struct neighbour *n, int type, int flags, 3313static void __neigh_notify(struct neighbour *n, int type, int flags,
3132 u32 pid) 3314 u32 pid)
3133{ 3315{
@@ -3511,7 +3693,7 @@ static int __init neigh_init(void)
3511{ 3693{
3512 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0); 3694 rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, 0);
3513 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0); 3695 rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, 0);
3514 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, 0); 3696 rtnl_register(PF_UNSPEC, RTM_GETNEIGH, neigh_get, neigh_dump_info, 0);
3515 3697
3516 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info, 3698 rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info,
3517 0); 3699 0);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index baf2685b4da2..48f61885fd6f 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -3460,18 +3460,6 @@ void rtmsg_ifinfo_newnet(int type, struct net_device *dev, unsigned int change,
3460 new_nsid, new_ifindex); 3460 new_nsid, new_ifindex);
3461} 3461}
3462 3462
3463static const struct nla_policy nda_policy[NDA_MAX+1] = {
3464 [NDA_DST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
3465 [NDA_LLADDR] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
3466 [NDA_CACHEINFO] = { .len = sizeof(struct nda_cacheinfo) },
3467 [NDA_PROBES] = { .type = NLA_U32 },
3468 [NDA_VLAN] = { .type = NLA_U16 },
3469 [NDA_PORT] = { .type = NLA_U16 },
3470 [NDA_VNI] = { .type = NLA_U32 },
3471 [NDA_IFINDEX] = { .type = NLA_U32 },
3472 [NDA_MASTER] = { .type = NLA_U32 },
3473};
3474
3475static int nlmsg_populate_fdb_fill(struct sk_buff *skb, 3463static int nlmsg_populate_fdb_fill(struct sk_buff *skb,
3476 struct net_device *dev, 3464 struct net_device *dev,
3477 u8 *addr, u16 vid, u32 pid, u32 seq, 3465 u8 *addr, u16 vid, u32 pid, u32 seq,