diff options
author | Patrick McHardy <kaber@trash.net> | 2010-05-11 08:40:56 -0400 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2010-05-11 08:40:56 -0400 |
commit | 5b285cac3570a935aaa28312c1ea28f9e01c5452 (patch) | |
tree | a39d8602eb21eb4a721fda933fe21b0c79d3d383 | |
parent | d1db275dd3f6e4182c4c4b4a1ac6287925d60569 (diff) |
ipv6: ip6mr: add support for dumping routing tables over netlink
The ip6mr /proc interface (ip6_mr_cache) can't be extended to dump routes
from any tables but the main table in a backwards compatible fashion since
the output format ends in a variable amount of output interfaces.
Introduce a new netlink interface to dump multicast routes from all tables,
similar to the netlink interface for regular routes.
Signed-off-by: Patrick McHardy <kaber@trash.net>
-rw-r--r-- | net/ipv6/ip6mr.c | 96 |
1 files changed, 89 insertions, 7 deletions
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index c2920a1a6db3..163850e22b11 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c | |||
@@ -112,8 +112,10 @@ static int ip6_mr_forward(struct net *net, struct mr6_table *mrt, | |||
112 | struct sk_buff *skb, struct mfc6_cache *cache); | 112 | struct sk_buff *skb, struct mfc6_cache *cache); |
113 | static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt, | 113 | static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt, |
114 | mifi_t mifi, int assert); | 114 | mifi_t mifi, int assert); |
115 | static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | 115 | static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, |
116 | struct mfc6_cache *c, struct rtmsg *rtm); | 116 | struct mfc6_cache *c, struct rtmsg *rtm); |
117 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, | ||
118 | struct netlink_callback *cb); | ||
117 | static void mroute_clean_tables(struct mr6_table *mrt); | 119 | static void mroute_clean_tables(struct mr6_table *mrt); |
118 | static void ipmr_expire_process(unsigned long arg); | 120 | static void ipmr_expire_process(unsigned long arg); |
119 | 121 | ||
@@ -1038,7 +1040,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt, | |||
1038 | int err; | 1040 | int err; |
1039 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); | 1041 | struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); |
1040 | 1042 | ||
1041 | if (ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) { | 1043 | if (__ip6mr_fill_mroute(mrt, skb, c, NLMSG_DATA(nlh)) > 0) { |
1042 | nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh; | 1044 | nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh; |
1043 | } else { | 1045 | } else { |
1044 | nlh->nlmsg_type = NLMSG_ERROR; | 1046 | nlh->nlmsg_type = NLMSG_ERROR; |
@@ -1350,6 +1352,7 @@ int __init ip6_mr_init(void) | |||
1350 | goto add_proto_fail; | 1352 | goto add_proto_fail; |
1351 | } | 1353 | } |
1352 | #endif | 1354 | #endif |
1355 | rtnl_register(RTNL_FAMILY_IP6MR, RTM_GETROUTE, NULL, ip6mr_rtm_dumproute); | ||
1353 | return 0; | 1356 | return 0; |
1354 | #ifdef CONFIG_IPV6_PIMSM_V2 | 1357 | #ifdef CONFIG_IPV6_PIMSM_V2 |
1355 | add_proto_fail: | 1358 | add_proto_fail: |
@@ -2007,9 +2010,8 @@ int ip6_mr_input(struct sk_buff *skb) | |||
2007 | } | 2010 | } |
2008 | 2011 | ||
2009 | 2012 | ||
2010 | static int | 2013 | static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, |
2011 | ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | 2014 | struct mfc6_cache *c, struct rtmsg *rtm) |
2012 | struct mfc6_cache *c, struct rtmsg *rtm) | ||
2013 | { | 2015 | { |
2014 | int ct; | 2016 | int ct; |
2015 | struct rtnexthop *nhp; | 2017 | struct rtnexthop *nhp; |
@@ -2111,8 +2113,88 @@ int ip6mr_get_route(struct net *net, | |||
2111 | if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY)) | 2113 | if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY)) |
2112 | cache->mfc_flags |= MFC_NOTIFY; | 2114 | cache->mfc_flags |= MFC_NOTIFY; |
2113 | 2115 | ||
2114 | err = ip6mr_fill_mroute(mrt, skb, cache, rtm); | 2116 | err = __ip6mr_fill_mroute(mrt, skb, cache, rtm); |
2115 | read_unlock(&mrt_lock); | 2117 | read_unlock(&mrt_lock); |
2116 | return err; | 2118 | return err; |
2117 | } | 2119 | } |
2118 | 2120 | ||
2121 | static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, | ||
2122 | u32 pid, u32 seq, struct mfc6_cache *c) | ||
2123 | { | ||
2124 | struct nlmsghdr *nlh; | ||
2125 | struct rtmsg *rtm; | ||
2126 | |||
2127 | nlh = nlmsg_put(skb, pid, seq, RTM_NEWROUTE, sizeof(*rtm), NLM_F_MULTI); | ||
2128 | if (nlh == NULL) | ||
2129 | return -EMSGSIZE; | ||
2130 | |||
2131 | rtm = nlmsg_data(nlh); | ||
2132 | rtm->rtm_family = RTNL_FAMILY_IPMR; | ||
2133 | rtm->rtm_dst_len = 128; | ||
2134 | rtm->rtm_src_len = 128; | ||
2135 | rtm->rtm_tos = 0; | ||
2136 | rtm->rtm_table = mrt->id; | ||
2137 | NLA_PUT_U32(skb, RTA_TABLE, mrt->id); | ||
2138 | rtm->rtm_scope = RT_SCOPE_UNIVERSE; | ||
2139 | rtm->rtm_protocol = RTPROT_UNSPEC; | ||
2140 | rtm->rtm_flags = 0; | ||
2141 | |||
2142 | NLA_PUT(skb, RTA_SRC, 16, &c->mf6c_origin); | ||
2143 | NLA_PUT(skb, RTA_DST, 16, &c->mf6c_mcastgrp); | ||
2144 | |||
2145 | if (__ip6mr_fill_mroute(mrt, skb, c, rtm) < 0) | ||
2146 | goto nla_put_failure; | ||
2147 | |||
2148 | return nlmsg_end(skb, nlh); | ||
2149 | |||
2150 | nla_put_failure: | ||
2151 | nlmsg_cancel(skb, nlh); | ||
2152 | return -EMSGSIZE; | ||
2153 | } | ||
2154 | |||
2155 | static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb) | ||
2156 | { | ||
2157 | struct net *net = sock_net(skb->sk); | ||
2158 | struct mr6_table *mrt; | ||
2159 | struct mfc6_cache *mfc; | ||
2160 | unsigned int t = 0, s_t; | ||
2161 | unsigned int h = 0, s_h; | ||
2162 | unsigned int e = 0, s_e; | ||
2163 | |||
2164 | s_t = cb->args[0]; | ||
2165 | s_h = cb->args[1]; | ||
2166 | s_e = cb->args[2]; | ||
2167 | |||
2168 | read_lock(&mrt_lock); | ||
2169 | ip6mr_for_each_table(mrt, net) { | ||
2170 | if (t < s_t) | ||
2171 | goto next_table; | ||
2172 | if (t > s_t) | ||
2173 | s_h = 0; | ||
2174 | for (h = s_h; h < MFC6_LINES; h++) { | ||
2175 | list_for_each_entry(mfc, &mrt->mfc6_cache_array[h], list) { | ||
2176 | if (e < s_e) | ||
2177 | goto next_entry; | ||
2178 | if (ip6mr_fill_mroute(mrt, skb, | ||
2179 | NETLINK_CB(cb->skb).pid, | ||
2180 | cb->nlh->nlmsg_seq, | ||
2181 | mfc) < 0) | ||
2182 | goto done; | ||
2183 | next_entry: | ||
2184 | e++; | ||
2185 | } | ||
2186 | e = s_e = 0; | ||
2187 | } | ||
2188 | s_h = 0; | ||
2189 | next_table: | ||
2190 | t++; | ||
2191 | } | ||
2192 | done: | ||
2193 | read_unlock(&mrt_lock); | ||
2194 | |||
2195 | cb->args[2] = e; | ||
2196 | cb->args[1] = h; | ||
2197 | cb->args[0] = t; | ||
2198 | |||
2199 | return skb->len; | ||
2200 | } | ||