aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2010-05-11 08:40:56 -0400
committerPatrick McHardy <kaber@trash.net>2010-05-11 08:40:56 -0400
commit5b285cac3570a935aaa28312c1ea28f9e01c5452 (patch)
treea39d8602eb21eb4a721fda933fe21b0c79d3d383 /net/ipv6
parentd1db275dd3f6e4182c4c4b4a1ac6287925d60569 (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>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ip6mr.c96
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);
113static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt, 113static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
114 mifi_t mifi, int assert); 114 mifi_t mifi, int assert);
115static int ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb, 115static 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);
117static int ip6mr_rtm_dumproute(struct sk_buff *skb,
118 struct netlink_callback *cb);
117static void mroute_clean_tables(struct mr6_table *mrt); 119static void mroute_clean_tables(struct mr6_table *mrt);
118static void ipmr_expire_process(unsigned long arg); 120static 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
1355add_proto_fail: 1358add_proto_fail:
@@ -2007,9 +2010,8 @@ int ip6_mr_input(struct sk_buff *skb)
2007} 2010}
2008 2011
2009 2012
2010static int 2013static int __ip6mr_fill_mroute(struct mr6_table *mrt, struct sk_buff *skb,
2011ip6mr_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
2121static 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
2150nla_put_failure:
2151 nlmsg_cancel(skb, nlh);
2152 return -EMSGSIZE;
2153}
2154
2155static 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;
2183next_entry:
2184 e++;
2185 }
2186 e = s_e = 0;
2187 }
2188 s_h = 0;
2189next_table:
2190 t++;
2191 }
2192done:
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}