xref: /openbmc/linux/net/ipv4/ipmr_base.c (revision 4cff79e9)
1 /* Linux multicast routing support
2  * Common logic shared by IPv4 [ipmr] and IPv6 [ip6mr] implementation
3  */
4 
5 #include <linux/mroute_base.h>
6 
7 /* Sets everything common except 'dev', since that is done under locking */
8 void vif_device_init(struct vif_device *v,
9 		     struct net_device *dev,
10 		     unsigned long rate_limit,
11 		     unsigned char threshold,
12 		     unsigned short flags,
13 		     unsigned short get_iflink_mask)
14 {
15 	v->dev = NULL;
16 	v->bytes_in = 0;
17 	v->bytes_out = 0;
18 	v->pkt_in = 0;
19 	v->pkt_out = 0;
20 	v->rate_limit = rate_limit;
21 	v->flags = flags;
22 	v->threshold = threshold;
23 	if (v->flags & get_iflink_mask)
24 		v->link = dev_get_iflink(dev);
25 	else
26 		v->link = dev->ifindex;
27 }
28 EXPORT_SYMBOL(vif_device_init);
29 
30 struct mr_table *
31 mr_table_alloc(struct net *net, u32 id,
32 	       struct mr_table_ops *ops,
33 	       void (*expire_func)(struct timer_list *t),
34 	       void (*table_set)(struct mr_table *mrt,
35 				 struct net *net))
36 {
37 	struct mr_table *mrt;
38 
39 	mrt = kzalloc(sizeof(*mrt), GFP_KERNEL);
40 	if (!mrt)
41 		return NULL;
42 	mrt->id = id;
43 	write_pnet(&mrt->net, net);
44 
45 	mrt->ops = *ops;
46 	rhltable_init(&mrt->mfc_hash, mrt->ops.rht_params);
47 	INIT_LIST_HEAD(&mrt->mfc_cache_list);
48 	INIT_LIST_HEAD(&mrt->mfc_unres_queue);
49 
50 	timer_setup(&mrt->ipmr_expire_timer, expire_func, 0);
51 
52 	mrt->mroute_reg_vif_num = -1;
53 	table_set(mrt, net);
54 	return mrt;
55 }
56 EXPORT_SYMBOL(mr_table_alloc);
57 
58 void *mr_mfc_find_parent(struct mr_table *mrt, void *hasharg, int parent)
59 {
60 	struct rhlist_head *tmp, *list;
61 	struct mr_mfc *c;
62 
63 	list = rhltable_lookup(&mrt->mfc_hash, hasharg, *mrt->ops.rht_params);
64 	rhl_for_each_entry_rcu(c, tmp, list, mnode)
65 		if (parent == -1 || parent == c->mfc_parent)
66 			return c;
67 
68 	return NULL;
69 }
70 EXPORT_SYMBOL(mr_mfc_find_parent);
71 
72 void *mr_mfc_find_any_parent(struct mr_table *mrt, int vifi)
73 {
74 	struct rhlist_head *tmp, *list;
75 	struct mr_mfc *c;
76 
77 	list = rhltable_lookup(&mrt->mfc_hash, mrt->ops.cmparg_any,
78 			       *mrt->ops.rht_params);
79 	rhl_for_each_entry_rcu(c, tmp, list, mnode)
80 		if (c->mfc_un.res.ttls[vifi] < 255)
81 			return c;
82 
83 	return NULL;
84 }
85 EXPORT_SYMBOL(mr_mfc_find_any_parent);
86 
87 void *mr_mfc_find_any(struct mr_table *mrt, int vifi, void *hasharg)
88 {
89 	struct rhlist_head *tmp, *list;
90 	struct mr_mfc *c, *proxy;
91 
92 	list = rhltable_lookup(&mrt->mfc_hash, hasharg, *mrt->ops.rht_params);
93 	rhl_for_each_entry_rcu(c, tmp, list, mnode) {
94 		if (c->mfc_un.res.ttls[vifi] < 255)
95 			return c;
96 
97 		/* It's ok if the vifi is part of the static tree */
98 		proxy = mr_mfc_find_any_parent(mrt, c->mfc_parent);
99 		if (proxy && proxy->mfc_un.res.ttls[vifi] < 255)
100 			return c;
101 	}
102 
103 	return mr_mfc_find_any_parent(mrt, vifi);
104 }
105 EXPORT_SYMBOL(mr_mfc_find_any);
106 
107 #ifdef CONFIG_PROC_FS
108 void *mr_vif_seq_idx(struct net *net, struct mr_vif_iter *iter, loff_t pos)
109 {
110 	struct mr_table *mrt = iter->mrt;
111 
112 	for (iter->ct = 0; iter->ct < mrt->maxvif; ++iter->ct) {
113 		if (!VIF_EXISTS(mrt, iter->ct))
114 			continue;
115 		if (pos-- == 0)
116 			return &mrt->vif_table[iter->ct];
117 	}
118 	return NULL;
119 }
120 EXPORT_SYMBOL(mr_vif_seq_idx);
121 
122 void *mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
123 {
124 	struct mr_vif_iter *iter = seq->private;
125 	struct net *net = seq_file_net(seq);
126 	struct mr_table *mrt = iter->mrt;
127 
128 	++*pos;
129 	if (v == SEQ_START_TOKEN)
130 		return mr_vif_seq_idx(net, iter, 0);
131 
132 	while (++iter->ct < mrt->maxvif) {
133 		if (!VIF_EXISTS(mrt, iter->ct))
134 			continue;
135 		return &mrt->vif_table[iter->ct];
136 	}
137 	return NULL;
138 }
139 EXPORT_SYMBOL(mr_vif_seq_next);
140 
141 void *mr_mfc_seq_idx(struct net *net,
142 		     struct mr_mfc_iter *it, loff_t pos)
143 {
144 	struct mr_table *mrt = it->mrt;
145 	struct mr_mfc *mfc;
146 
147 	rcu_read_lock();
148 	it->cache = &mrt->mfc_cache_list;
149 	list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list)
150 		if (pos-- == 0)
151 			return mfc;
152 	rcu_read_unlock();
153 
154 	spin_lock_bh(it->lock);
155 	it->cache = &mrt->mfc_unres_queue;
156 	list_for_each_entry(mfc, it->cache, list)
157 		if (pos-- == 0)
158 			return mfc;
159 	spin_unlock_bh(it->lock);
160 
161 	it->cache = NULL;
162 	return NULL;
163 }
164 EXPORT_SYMBOL(mr_mfc_seq_idx);
165 
166 void *mr_mfc_seq_next(struct seq_file *seq, void *v,
167 		      loff_t *pos)
168 {
169 	struct mr_mfc_iter *it = seq->private;
170 	struct net *net = seq_file_net(seq);
171 	struct mr_table *mrt = it->mrt;
172 	struct mr_mfc *c = v;
173 
174 	++*pos;
175 
176 	if (v == SEQ_START_TOKEN)
177 		return mr_mfc_seq_idx(net, seq->private, 0);
178 
179 	if (c->list.next != it->cache)
180 		return list_entry(c->list.next, struct mr_mfc, list);
181 
182 	if (it->cache == &mrt->mfc_unres_queue)
183 		goto end_of_list;
184 
185 	/* exhausted cache_array, show unresolved */
186 	rcu_read_unlock();
187 	it->cache = &mrt->mfc_unres_queue;
188 
189 	spin_lock_bh(it->lock);
190 	if (!list_empty(it->cache))
191 		return list_first_entry(it->cache, struct mr_mfc, list);
192 
193 end_of_list:
194 	spin_unlock_bh(it->lock);
195 	it->cache = NULL;
196 
197 	return NULL;
198 }
199 EXPORT_SYMBOL(mr_mfc_seq_next);
200 #endif
201 
202 int mr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
203 		   struct mr_mfc *c, struct rtmsg *rtm)
204 {
205 	struct rta_mfc_stats mfcs;
206 	struct nlattr *mp_attr;
207 	struct rtnexthop *nhp;
208 	unsigned long lastuse;
209 	int ct;
210 
211 	/* If cache is unresolved, don't try to parse IIF and OIF */
212 	if (c->mfc_parent >= MAXVIFS) {
213 		rtm->rtm_flags |= RTNH_F_UNRESOLVED;
214 		return -ENOENT;
215 	}
216 
217 	if (VIF_EXISTS(mrt, c->mfc_parent) &&
218 	    nla_put_u32(skb, RTA_IIF,
219 			mrt->vif_table[c->mfc_parent].dev->ifindex) < 0)
220 		return -EMSGSIZE;
221 
222 	if (c->mfc_flags & MFC_OFFLOAD)
223 		rtm->rtm_flags |= RTNH_F_OFFLOAD;
224 
225 	mp_attr = nla_nest_start(skb, RTA_MULTIPATH);
226 	if (!mp_attr)
227 		return -EMSGSIZE;
228 
229 	for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
230 		if (VIF_EXISTS(mrt, ct) && c->mfc_un.res.ttls[ct] < 255) {
231 			struct vif_device *vif;
232 
233 			nhp = nla_reserve_nohdr(skb, sizeof(*nhp));
234 			if (!nhp) {
235 				nla_nest_cancel(skb, mp_attr);
236 				return -EMSGSIZE;
237 			}
238 
239 			nhp->rtnh_flags = 0;
240 			nhp->rtnh_hops = c->mfc_un.res.ttls[ct];
241 			vif = &mrt->vif_table[ct];
242 			nhp->rtnh_ifindex = vif->dev->ifindex;
243 			nhp->rtnh_len = sizeof(*nhp);
244 		}
245 	}
246 
247 	nla_nest_end(skb, mp_attr);
248 
249 	lastuse = READ_ONCE(c->mfc_un.res.lastuse);
250 	lastuse = time_after_eq(jiffies, lastuse) ? jiffies - lastuse : 0;
251 
252 	mfcs.mfcs_packets = c->mfc_un.res.pkt;
253 	mfcs.mfcs_bytes = c->mfc_un.res.bytes;
254 	mfcs.mfcs_wrong_if = c->mfc_un.res.wrong_if;
255 	if (nla_put_64bit(skb, RTA_MFC_STATS, sizeof(mfcs), &mfcs, RTA_PAD) ||
256 	    nla_put_u64_64bit(skb, RTA_EXPIRES, jiffies_to_clock_t(lastuse),
257 			      RTA_PAD))
258 		return -EMSGSIZE;
259 
260 	rtm->rtm_type = RTN_MULTICAST;
261 	return 1;
262 }
263 EXPORT_SYMBOL(mr_fill_mroute);
264 
265 int mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb,
266 		     struct mr_table *(*iter)(struct net *net,
267 					      struct mr_table *mrt),
268 		     int (*fill)(struct mr_table *mrt,
269 				 struct sk_buff *skb,
270 				 u32 portid, u32 seq, struct mr_mfc *c,
271 				 int cmd, int flags),
272 		     spinlock_t *lock)
273 {
274 	unsigned int t = 0, e = 0, s_t = cb->args[0], s_e = cb->args[1];
275 	struct net *net = sock_net(skb->sk);
276 	struct mr_table *mrt;
277 	struct mr_mfc *mfc;
278 
279 	rcu_read_lock();
280 	for (mrt = iter(net, NULL); mrt; mrt = iter(net, mrt)) {
281 		if (t < s_t)
282 			goto next_table;
283 		list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list) {
284 			if (e < s_e)
285 				goto next_entry;
286 			if (fill(mrt, skb, NETLINK_CB(cb->skb).portid,
287 				 cb->nlh->nlmsg_seq, mfc,
288 				 RTM_NEWROUTE, NLM_F_MULTI) < 0)
289 				goto done;
290 next_entry:
291 			e++;
292 		}
293 		e = 0;
294 		s_e = 0;
295 
296 		spin_lock_bh(lock);
297 		list_for_each_entry(mfc, &mrt->mfc_unres_queue, list) {
298 			if (e < s_e)
299 				goto next_entry2;
300 			if (fill(mrt, skb, NETLINK_CB(cb->skb).portid,
301 				 cb->nlh->nlmsg_seq, mfc,
302 				 RTM_NEWROUTE, NLM_F_MULTI) < 0) {
303 				spin_unlock_bh(lock);
304 				goto done;
305 			}
306 next_entry2:
307 			e++;
308 		}
309 		spin_unlock_bh(lock);
310 		e = 0;
311 		s_e = 0;
312 next_table:
313 		t++;
314 	}
315 done:
316 	rcu_read_unlock();
317 
318 	cb->args[1] = e;
319 	cb->args[0] = t;
320 
321 	return skb->len;
322 }
323 EXPORT_SYMBOL(mr_rtm_dumproute);
324 
325 int mr_dump(struct net *net, struct notifier_block *nb, unsigned short family,
326 	    int (*rules_dump)(struct net *net,
327 			      struct notifier_block *nb),
328 	    struct mr_table *(*mr_iter)(struct net *net,
329 					struct mr_table *mrt),
330 	    rwlock_t *mrt_lock)
331 {
332 	struct mr_table *mrt;
333 	int err;
334 
335 	err = rules_dump(net, nb);
336 	if (err)
337 		return err;
338 
339 	for (mrt = mr_iter(net, NULL); mrt; mrt = mr_iter(net, mrt)) {
340 		struct vif_device *v = &mrt->vif_table[0];
341 		struct mr_mfc *mfc;
342 		int vifi;
343 
344 		/* Notifiy on table VIF entries */
345 		read_lock(mrt_lock);
346 		for (vifi = 0; vifi < mrt->maxvif; vifi++, v++) {
347 			if (!v->dev)
348 				continue;
349 
350 			mr_call_vif_notifier(nb, net, family,
351 					     FIB_EVENT_VIF_ADD,
352 					     v, vifi, mrt->id);
353 		}
354 		read_unlock(mrt_lock);
355 
356 		/* Notify on table MFC entries */
357 		list_for_each_entry_rcu(mfc, &mrt->mfc_cache_list, list)
358 			mr_call_mfc_notifier(nb, net, family,
359 					     FIB_EVENT_ENTRY_ADD,
360 					     mfc, mrt->id);
361 	}
362 
363 	return 0;
364 }
365 EXPORT_SYMBOL(mr_dump);
366