xref: /OK3568_Linux_fs/kernel/net/mpls/af_mpls.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun #include <linux/types.h>
3*4882a593Smuzhiyun #include <linux/skbuff.h>
4*4882a593Smuzhiyun #include <linux/socket.h>
5*4882a593Smuzhiyun #include <linux/sysctl.h>
6*4882a593Smuzhiyun #include <linux/net.h>
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/if_arp.h>
9*4882a593Smuzhiyun #include <linux/ipv6.h>
10*4882a593Smuzhiyun #include <linux/mpls.h>
11*4882a593Smuzhiyun #include <linux/netconf.h>
12*4882a593Smuzhiyun #include <linux/nospec.h>
13*4882a593Smuzhiyun #include <linux/vmalloc.h>
14*4882a593Smuzhiyun #include <linux/percpu.h>
15*4882a593Smuzhiyun #include <net/ip.h>
16*4882a593Smuzhiyun #include <net/dst.h>
17*4882a593Smuzhiyun #include <net/sock.h>
18*4882a593Smuzhiyun #include <net/arp.h>
19*4882a593Smuzhiyun #include <net/ip_fib.h>
20*4882a593Smuzhiyun #include <net/netevent.h>
21*4882a593Smuzhiyun #include <net/ip_tunnels.h>
22*4882a593Smuzhiyun #include <net/netns/generic.h>
23*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
24*4882a593Smuzhiyun #include <net/ipv6.h>
25*4882a593Smuzhiyun #endif
26*4882a593Smuzhiyun #include <net/ipv6_stubs.h>
27*4882a593Smuzhiyun #include <net/rtnh.h>
28*4882a593Smuzhiyun #include "internal.h"
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /* max memory we will use for mpls_route */
31*4882a593Smuzhiyun #define MAX_MPLS_ROUTE_MEM	4096
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /* Maximum number of labels to look ahead at when selecting a path of
34*4882a593Smuzhiyun  * a multipath route
35*4882a593Smuzhiyun  */
36*4882a593Smuzhiyun #define MAX_MP_SELECT_LABELS 4
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define MPLS_NEIGH_TABLE_UNSPEC (NEIGH_LINK_TABLE + 1)
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun static int label_limit = (1 << 20) - 1;
41*4882a593Smuzhiyun static int ttl_max = 255;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_NET_IP_TUNNEL)
ipgre_mpls_encap_hlen(struct ip_tunnel_encap * e)44*4882a593Smuzhiyun static size_t ipgre_mpls_encap_hlen(struct ip_tunnel_encap *e)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	return sizeof(struct mpls_shim_hdr);
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun static const struct ip_tunnel_encap_ops mpls_iptun_ops = {
50*4882a593Smuzhiyun 	.encap_hlen	= ipgre_mpls_encap_hlen,
51*4882a593Smuzhiyun };
52*4882a593Smuzhiyun 
ipgre_tunnel_encap_add_mpls_ops(void)53*4882a593Smuzhiyun static int ipgre_tunnel_encap_add_mpls_ops(void)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	return ip_tunnel_encap_add_ops(&mpls_iptun_ops, TUNNEL_ENCAP_MPLS);
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun 
ipgre_tunnel_encap_del_mpls_ops(void)58*4882a593Smuzhiyun static void ipgre_tunnel_encap_del_mpls_ops(void)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	ip_tunnel_encap_del_ops(&mpls_iptun_ops, TUNNEL_ENCAP_MPLS);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun #else
ipgre_tunnel_encap_add_mpls_ops(void)63*4882a593Smuzhiyun static int ipgre_tunnel_encap_add_mpls_ops(void)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	return 0;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
ipgre_tunnel_encap_del_mpls_ops(void)68*4882a593Smuzhiyun static void ipgre_tunnel_encap_del_mpls_ops(void)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun #endif
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun static void rtmsg_lfib(int event, u32 label, struct mpls_route *rt,
74*4882a593Smuzhiyun 		       struct nlmsghdr *nlh, struct net *net, u32 portid,
75*4882a593Smuzhiyun 		       unsigned int nlm_flags);
76*4882a593Smuzhiyun 
mpls_route_input_rcu(struct net * net,unsigned index)77*4882a593Smuzhiyun static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	struct mpls_route *rt = NULL;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	if (index < net->mpls.platform_labels) {
82*4882a593Smuzhiyun 		struct mpls_route __rcu **platform_label =
83*4882a593Smuzhiyun 			rcu_dereference(net->mpls.platform_label);
84*4882a593Smuzhiyun 		rt = rcu_dereference(platform_label[index]);
85*4882a593Smuzhiyun 	}
86*4882a593Smuzhiyun 	return rt;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
mpls_output_possible(const struct net_device * dev)89*4882a593Smuzhiyun bool mpls_output_possible(const struct net_device *dev)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	return dev && (dev->flags & IFF_UP) && netif_carrier_ok(dev);
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mpls_output_possible);
94*4882a593Smuzhiyun 
__mpls_nh_via(struct mpls_route * rt,struct mpls_nh * nh)95*4882a593Smuzhiyun static u8 *__mpls_nh_via(struct mpls_route *rt, struct mpls_nh *nh)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	return (u8 *)nh + rt->rt_via_offset;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
mpls_nh_via(const struct mpls_route * rt,const struct mpls_nh * nh)100*4882a593Smuzhiyun static const u8 *mpls_nh_via(const struct mpls_route *rt,
101*4882a593Smuzhiyun 			     const struct mpls_nh *nh)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	return __mpls_nh_via((struct mpls_route *)rt, (struct mpls_nh *)nh);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
mpls_nh_header_size(const struct mpls_nh * nh)106*4882a593Smuzhiyun static unsigned int mpls_nh_header_size(const struct mpls_nh *nh)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun 	/* The size of the layer 2.5 labels to be added for this route */
109*4882a593Smuzhiyun 	return nh->nh_labels * sizeof(struct mpls_shim_hdr);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
mpls_dev_mtu(const struct net_device * dev)112*4882a593Smuzhiyun unsigned int mpls_dev_mtu(const struct net_device *dev)
113*4882a593Smuzhiyun {
114*4882a593Smuzhiyun 	/* The amount of data the layer 2 frame can hold */
115*4882a593Smuzhiyun 	return dev->mtu;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mpls_dev_mtu);
118*4882a593Smuzhiyun 
mpls_pkt_too_big(const struct sk_buff * skb,unsigned int mtu)119*4882a593Smuzhiyun bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun 	if (skb->len <= mtu)
122*4882a593Smuzhiyun 		return false;
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun 	if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
125*4882a593Smuzhiyun 		return false;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	return true;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mpls_pkt_too_big);
130*4882a593Smuzhiyun 
mpls_stats_inc_outucastpkts(struct net_device * dev,const struct sk_buff * skb)131*4882a593Smuzhiyun void mpls_stats_inc_outucastpkts(struct net_device *dev,
132*4882a593Smuzhiyun 				 const struct sk_buff *skb)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	struct mpls_dev *mdev;
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	if (skb->protocol == htons(ETH_P_MPLS_UC)) {
137*4882a593Smuzhiyun 		mdev = mpls_dev_get(dev);
138*4882a593Smuzhiyun 		if (mdev)
139*4882a593Smuzhiyun 			MPLS_INC_STATS_LEN(mdev, skb->len,
140*4882a593Smuzhiyun 					   tx_packets,
141*4882a593Smuzhiyun 					   tx_bytes);
142*4882a593Smuzhiyun 	} else if (skb->protocol == htons(ETH_P_IP)) {
143*4882a593Smuzhiyun 		IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len);
144*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
145*4882a593Smuzhiyun 	} else if (skb->protocol == htons(ETH_P_IPV6)) {
146*4882a593Smuzhiyun 		struct inet6_dev *in6dev = __in6_dev_get(dev);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 		if (in6dev)
149*4882a593Smuzhiyun 			IP6_UPD_PO_STATS(dev_net(dev), in6dev,
150*4882a593Smuzhiyun 					 IPSTATS_MIB_OUT, skb->len);
151*4882a593Smuzhiyun #endif
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(mpls_stats_inc_outucastpkts);
155*4882a593Smuzhiyun 
mpls_multipath_hash(struct mpls_route * rt,struct sk_buff * skb)156*4882a593Smuzhiyun static u32 mpls_multipath_hash(struct mpls_route *rt, struct sk_buff *skb)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	struct mpls_entry_decoded dec;
159*4882a593Smuzhiyun 	unsigned int mpls_hdr_len = 0;
160*4882a593Smuzhiyun 	struct mpls_shim_hdr *hdr;
161*4882a593Smuzhiyun 	bool eli_seen = false;
162*4882a593Smuzhiyun 	int label_index;
163*4882a593Smuzhiyun 	u32 hash = 0;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	for (label_index = 0; label_index < MAX_MP_SELECT_LABELS;
166*4882a593Smuzhiyun 	     label_index++) {
167*4882a593Smuzhiyun 		mpls_hdr_len += sizeof(*hdr);
168*4882a593Smuzhiyun 		if (!pskb_may_pull(skb, mpls_hdr_len))
169*4882a593Smuzhiyun 			break;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 		/* Read and decode the current label */
172*4882a593Smuzhiyun 		hdr = mpls_hdr(skb) + label_index;
173*4882a593Smuzhiyun 		dec = mpls_entry_decode(hdr);
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 		/* RFC6790 - reserved labels MUST NOT be used as keys
176*4882a593Smuzhiyun 		 * for the load-balancing function
177*4882a593Smuzhiyun 		 */
178*4882a593Smuzhiyun 		if (likely(dec.label >= MPLS_LABEL_FIRST_UNRESERVED)) {
179*4882a593Smuzhiyun 			hash = jhash_1word(dec.label, hash);
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 			/* The entropy label follows the entropy label
182*4882a593Smuzhiyun 			 * indicator, so this means that the entropy
183*4882a593Smuzhiyun 			 * label was just added to the hash - no need to
184*4882a593Smuzhiyun 			 * go any deeper either in the label stack or in the
185*4882a593Smuzhiyun 			 * payload
186*4882a593Smuzhiyun 			 */
187*4882a593Smuzhiyun 			if (eli_seen)
188*4882a593Smuzhiyun 				break;
189*4882a593Smuzhiyun 		} else if (dec.label == MPLS_LABEL_ENTROPY) {
190*4882a593Smuzhiyun 			eli_seen = true;
191*4882a593Smuzhiyun 		}
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 		if (!dec.bos)
194*4882a593Smuzhiyun 			continue;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 		/* found bottom label; does skb have room for a header? */
197*4882a593Smuzhiyun 		if (pskb_may_pull(skb, mpls_hdr_len + sizeof(struct iphdr))) {
198*4882a593Smuzhiyun 			const struct iphdr *v4hdr;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 			v4hdr = (const struct iphdr *)(hdr + 1);
201*4882a593Smuzhiyun 			if (v4hdr->version == 4) {
202*4882a593Smuzhiyun 				hash = jhash_3words(ntohl(v4hdr->saddr),
203*4882a593Smuzhiyun 						    ntohl(v4hdr->daddr),
204*4882a593Smuzhiyun 						    v4hdr->protocol, hash);
205*4882a593Smuzhiyun 			} else if (v4hdr->version == 6 &&
206*4882a593Smuzhiyun 				   pskb_may_pull(skb, mpls_hdr_len +
207*4882a593Smuzhiyun 						 sizeof(struct ipv6hdr))) {
208*4882a593Smuzhiyun 				const struct ipv6hdr *v6hdr;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 				v6hdr = (const struct ipv6hdr *)(hdr + 1);
211*4882a593Smuzhiyun 				hash = __ipv6_addr_jhash(&v6hdr->saddr, hash);
212*4882a593Smuzhiyun 				hash = __ipv6_addr_jhash(&v6hdr->daddr, hash);
213*4882a593Smuzhiyun 				hash = jhash_1word(v6hdr->nexthdr, hash);
214*4882a593Smuzhiyun 			}
215*4882a593Smuzhiyun 		}
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 		break;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	return hash;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun 
mpls_get_nexthop(struct mpls_route * rt,u8 index)223*4882a593Smuzhiyun static struct mpls_nh *mpls_get_nexthop(struct mpls_route *rt, u8 index)
224*4882a593Smuzhiyun {
225*4882a593Smuzhiyun 	return (struct mpls_nh *)((u8 *)rt->rt_nh + index * rt->rt_nh_size);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun /* number of alive nexthops (rt->rt_nhn_alive) and the flags for
229*4882a593Smuzhiyun  * a next hop (nh->nh_flags) are modified by netdev event handlers.
230*4882a593Smuzhiyun  * Since those fields can change at any moment, use READ_ONCE to
231*4882a593Smuzhiyun  * access both.
232*4882a593Smuzhiyun  */
mpls_select_multipath(struct mpls_route * rt,struct sk_buff * skb)233*4882a593Smuzhiyun static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt,
234*4882a593Smuzhiyun 					     struct sk_buff *skb)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	u32 hash = 0;
237*4882a593Smuzhiyun 	int nh_index = 0;
238*4882a593Smuzhiyun 	int n = 0;
239*4882a593Smuzhiyun 	u8 alive;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	/* No need to look further into packet if there's only
242*4882a593Smuzhiyun 	 * one path
243*4882a593Smuzhiyun 	 */
244*4882a593Smuzhiyun 	if (rt->rt_nhn == 1)
245*4882a593Smuzhiyun 		return rt->rt_nh;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	alive = READ_ONCE(rt->rt_nhn_alive);
248*4882a593Smuzhiyun 	if (alive == 0)
249*4882a593Smuzhiyun 		return NULL;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	hash = mpls_multipath_hash(rt, skb);
252*4882a593Smuzhiyun 	nh_index = hash % alive;
253*4882a593Smuzhiyun 	if (alive == rt->rt_nhn)
254*4882a593Smuzhiyun 		goto out;
255*4882a593Smuzhiyun 	for_nexthops(rt) {
256*4882a593Smuzhiyun 		unsigned int nh_flags = READ_ONCE(nh->nh_flags);
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 		if (nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN))
259*4882a593Smuzhiyun 			continue;
260*4882a593Smuzhiyun 		if (n == nh_index)
261*4882a593Smuzhiyun 			return nh;
262*4882a593Smuzhiyun 		n++;
263*4882a593Smuzhiyun 	} endfor_nexthops(rt);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun out:
266*4882a593Smuzhiyun 	return mpls_get_nexthop(rt, nh_index);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
mpls_egress(struct net * net,struct mpls_route * rt,struct sk_buff * skb,struct mpls_entry_decoded dec)269*4882a593Smuzhiyun static bool mpls_egress(struct net *net, struct mpls_route *rt,
270*4882a593Smuzhiyun 			struct sk_buff *skb, struct mpls_entry_decoded dec)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun 	enum mpls_payload_type payload_type;
273*4882a593Smuzhiyun 	bool success = false;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	/* The IPv4 code below accesses through the IPv4 header
276*4882a593Smuzhiyun 	 * checksum, which is 12 bytes into the packet.
277*4882a593Smuzhiyun 	 * The IPv6 code below accesses through the IPv6 hop limit
278*4882a593Smuzhiyun 	 * which is 8 bytes into the packet.
279*4882a593Smuzhiyun 	 *
280*4882a593Smuzhiyun 	 * For all supported cases there should always be at least 12
281*4882a593Smuzhiyun 	 * bytes of packet data present.  The IPv4 header is 20 bytes
282*4882a593Smuzhiyun 	 * without options and the IPv6 header is always 40 bytes
283*4882a593Smuzhiyun 	 * long.
284*4882a593Smuzhiyun 	 */
285*4882a593Smuzhiyun 	if (!pskb_may_pull(skb, 12))
286*4882a593Smuzhiyun 		return false;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	payload_type = rt->rt_payload_type;
289*4882a593Smuzhiyun 	if (payload_type == MPT_UNSPEC)
290*4882a593Smuzhiyun 		payload_type = ip_hdr(skb)->version;
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	switch (payload_type) {
293*4882a593Smuzhiyun 	case MPT_IPV4: {
294*4882a593Smuzhiyun 		struct iphdr *hdr4 = ip_hdr(skb);
295*4882a593Smuzhiyun 		u8 new_ttl;
296*4882a593Smuzhiyun 		skb->protocol = htons(ETH_P_IP);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 		/* If propagating TTL, take the decremented TTL from
299*4882a593Smuzhiyun 		 * the incoming MPLS header, otherwise decrement the
300*4882a593Smuzhiyun 		 * TTL, but only if not 0 to avoid underflow.
301*4882a593Smuzhiyun 		 */
302*4882a593Smuzhiyun 		if (rt->rt_ttl_propagate == MPLS_TTL_PROP_ENABLED ||
303*4882a593Smuzhiyun 		    (rt->rt_ttl_propagate == MPLS_TTL_PROP_DEFAULT &&
304*4882a593Smuzhiyun 		     net->mpls.ip_ttl_propagate))
305*4882a593Smuzhiyun 			new_ttl = dec.ttl;
306*4882a593Smuzhiyun 		else
307*4882a593Smuzhiyun 			new_ttl = hdr4->ttl ? hdr4->ttl - 1 : 0;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 		csum_replace2(&hdr4->check,
310*4882a593Smuzhiyun 			      htons(hdr4->ttl << 8),
311*4882a593Smuzhiyun 			      htons(new_ttl << 8));
312*4882a593Smuzhiyun 		hdr4->ttl = new_ttl;
313*4882a593Smuzhiyun 		success = true;
314*4882a593Smuzhiyun 		break;
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 	case MPT_IPV6: {
317*4882a593Smuzhiyun 		struct ipv6hdr *hdr6 = ipv6_hdr(skb);
318*4882a593Smuzhiyun 		skb->protocol = htons(ETH_P_IPV6);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 		/* If propagating TTL, take the decremented TTL from
321*4882a593Smuzhiyun 		 * the incoming MPLS header, otherwise decrement the
322*4882a593Smuzhiyun 		 * hop limit, but only if not 0 to avoid underflow.
323*4882a593Smuzhiyun 		 */
324*4882a593Smuzhiyun 		if (rt->rt_ttl_propagate == MPLS_TTL_PROP_ENABLED ||
325*4882a593Smuzhiyun 		    (rt->rt_ttl_propagate == MPLS_TTL_PROP_DEFAULT &&
326*4882a593Smuzhiyun 		     net->mpls.ip_ttl_propagate))
327*4882a593Smuzhiyun 			hdr6->hop_limit = dec.ttl;
328*4882a593Smuzhiyun 		else if (hdr6->hop_limit)
329*4882a593Smuzhiyun 			hdr6->hop_limit = hdr6->hop_limit - 1;
330*4882a593Smuzhiyun 		success = true;
331*4882a593Smuzhiyun 		break;
332*4882a593Smuzhiyun 	}
333*4882a593Smuzhiyun 	case MPT_UNSPEC:
334*4882a593Smuzhiyun 		/* Should have decided which protocol it is by now */
335*4882a593Smuzhiyun 		break;
336*4882a593Smuzhiyun 	}
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	return success;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun 
mpls_forward(struct sk_buff * skb,struct net_device * dev,struct packet_type * pt,struct net_device * orig_dev)341*4882a593Smuzhiyun static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
342*4882a593Smuzhiyun 			struct packet_type *pt, struct net_device *orig_dev)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	struct net *net = dev_net(dev);
345*4882a593Smuzhiyun 	struct mpls_shim_hdr *hdr;
346*4882a593Smuzhiyun 	struct mpls_route *rt;
347*4882a593Smuzhiyun 	struct mpls_nh *nh;
348*4882a593Smuzhiyun 	struct mpls_entry_decoded dec;
349*4882a593Smuzhiyun 	struct net_device *out_dev;
350*4882a593Smuzhiyun 	struct mpls_dev *out_mdev;
351*4882a593Smuzhiyun 	struct mpls_dev *mdev;
352*4882a593Smuzhiyun 	unsigned int hh_len;
353*4882a593Smuzhiyun 	unsigned int new_header_size;
354*4882a593Smuzhiyun 	unsigned int mtu;
355*4882a593Smuzhiyun 	int err;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	/* Careful this entire function runs inside of an rcu critical section */
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	mdev = mpls_dev_get(dev);
360*4882a593Smuzhiyun 	if (!mdev)
361*4882a593Smuzhiyun 		goto drop;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	MPLS_INC_STATS_LEN(mdev, skb->len, rx_packets,
364*4882a593Smuzhiyun 			   rx_bytes);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	if (!mdev->input_enabled) {
367*4882a593Smuzhiyun 		MPLS_INC_STATS(mdev, rx_dropped);
368*4882a593Smuzhiyun 		goto drop;
369*4882a593Smuzhiyun 	}
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	if (skb->pkt_type != PACKET_HOST)
372*4882a593Smuzhiyun 		goto err;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
375*4882a593Smuzhiyun 		goto err;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	if (!pskb_may_pull(skb, sizeof(*hdr)))
378*4882a593Smuzhiyun 		goto err;
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	/* Read and decode the label */
381*4882a593Smuzhiyun 	hdr = mpls_hdr(skb);
382*4882a593Smuzhiyun 	dec = mpls_entry_decode(hdr);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	rt = mpls_route_input_rcu(net, dec.label);
385*4882a593Smuzhiyun 	if (!rt) {
386*4882a593Smuzhiyun 		MPLS_INC_STATS(mdev, rx_noroute);
387*4882a593Smuzhiyun 		goto drop;
388*4882a593Smuzhiyun 	}
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	nh = mpls_select_multipath(rt, skb);
391*4882a593Smuzhiyun 	if (!nh)
392*4882a593Smuzhiyun 		goto err;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	/* Pop the label */
395*4882a593Smuzhiyun 	skb_pull(skb, sizeof(*hdr));
396*4882a593Smuzhiyun 	skb_reset_network_header(skb);
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	skb_orphan(skb);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	if (skb_warn_if_lro(skb))
401*4882a593Smuzhiyun 		goto err;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	skb_forward_csum(skb);
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	/* Verify ttl is valid */
406*4882a593Smuzhiyun 	if (dec.ttl <= 1)
407*4882a593Smuzhiyun 		goto err;
408*4882a593Smuzhiyun 	dec.ttl -= 1;
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	/* Find the output device */
411*4882a593Smuzhiyun 	out_dev = rcu_dereference(nh->nh_dev);
412*4882a593Smuzhiyun 	if (!mpls_output_possible(out_dev))
413*4882a593Smuzhiyun 		goto tx_err;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	/* Verify the destination can hold the packet */
416*4882a593Smuzhiyun 	new_header_size = mpls_nh_header_size(nh);
417*4882a593Smuzhiyun 	mtu = mpls_dev_mtu(out_dev);
418*4882a593Smuzhiyun 	if (mpls_pkt_too_big(skb, mtu - new_header_size))
419*4882a593Smuzhiyun 		goto tx_err;
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	hh_len = LL_RESERVED_SPACE(out_dev);
422*4882a593Smuzhiyun 	if (!out_dev->header_ops)
423*4882a593Smuzhiyun 		hh_len = 0;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	/* Ensure there is enough space for the headers in the skb */
426*4882a593Smuzhiyun 	if (skb_cow(skb, hh_len + new_header_size))
427*4882a593Smuzhiyun 		goto tx_err;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	skb->dev = out_dev;
430*4882a593Smuzhiyun 	skb->protocol = htons(ETH_P_MPLS_UC);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	if (unlikely(!new_header_size && dec.bos)) {
433*4882a593Smuzhiyun 		/* Penultimate hop popping */
434*4882a593Smuzhiyun 		if (!mpls_egress(dev_net(out_dev), rt, skb, dec))
435*4882a593Smuzhiyun 			goto err;
436*4882a593Smuzhiyun 	} else {
437*4882a593Smuzhiyun 		bool bos;
438*4882a593Smuzhiyun 		int i;
439*4882a593Smuzhiyun 		skb_push(skb, new_header_size);
440*4882a593Smuzhiyun 		skb_reset_network_header(skb);
441*4882a593Smuzhiyun 		/* Push the new labels */
442*4882a593Smuzhiyun 		hdr = mpls_hdr(skb);
443*4882a593Smuzhiyun 		bos = dec.bos;
444*4882a593Smuzhiyun 		for (i = nh->nh_labels - 1; i >= 0; i--) {
445*4882a593Smuzhiyun 			hdr[i] = mpls_entry_encode(nh->nh_label[i],
446*4882a593Smuzhiyun 						   dec.ttl, 0, bos);
447*4882a593Smuzhiyun 			bos = false;
448*4882a593Smuzhiyun 		}
449*4882a593Smuzhiyun 	}
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	mpls_stats_inc_outucastpkts(out_dev, skb);
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	/* If via wasn't specified then send out using device address */
454*4882a593Smuzhiyun 	if (nh->nh_via_table == MPLS_NEIGH_TABLE_UNSPEC)
455*4882a593Smuzhiyun 		err = neigh_xmit(NEIGH_LINK_TABLE, out_dev,
456*4882a593Smuzhiyun 				 out_dev->dev_addr, skb);
457*4882a593Smuzhiyun 	else
458*4882a593Smuzhiyun 		err = neigh_xmit(nh->nh_via_table, out_dev,
459*4882a593Smuzhiyun 				 mpls_nh_via(rt, nh), skb);
460*4882a593Smuzhiyun 	if (err)
461*4882a593Smuzhiyun 		net_dbg_ratelimited("%s: packet transmission failed: %d\n",
462*4882a593Smuzhiyun 				    __func__, err);
463*4882a593Smuzhiyun 	return 0;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun tx_err:
466*4882a593Smuzhiyun 	out_mdev = out_dev ? mpls_dev_get(out_dev) : NULL;
467*4882a593Smuzhiyun 	if (out_mdev)
468*4882a593Smuzhiyun 		MPLS_INC_STATS(out_mdev, tx_errors);
469*4882a593Smuzhiyun 	goto drop;
470*4882a593Smuzhiyun err:
471*4882a593Smuzhiyun 	MPLS_INC_STATS(mdev, rx_errors);
472*4882a593Smuzhiyun drop:
473*4882a593Smuzhiyun 	kfree_skb(skb);
474*4882a593Smuzhiyun 	return NET_RX_DROP;
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun static struct packet_type mpls_packet_type __read_mostly = {
478*4882a593Smuzhiyun 	.type = cpu_to_be16(ETH_P_MPLS_UC),
479*4882a593Smuzhiyun 	.func = mpls_forward,
480*4882a593Smuzhiyun };
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun static const struct nla_policy rtm_mpls_policy[RTA_MAX+1] = {
483*4882a593Smuzhiyun 	[RTA_DST]		= { .type = NLA_U32 },
484*4882a593Smuzhiyun 	[RTA_OIF]		= { .type = NLA_U32 },
485*4882a593Smuzhiyun 	[RTA_TTL_PROPAGATE]	= { .type = NLA_U8 },
486*4882a593Smuzhiyun };
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun struct mpls_route_config {
489*4882a593Smuzhiyun 	u32			rc_protocol;
490*4882a593Smuzhiyun 	u32			rc_ifindex;
491*4882a593Smuzhiyun 	u8			rc_via_table;
492*4882a593Smuzhiyun 	u8			rc_via_alen;
493*4882a593Smuzhiyun 	u8			rc_via[MAX_VIA_ALEN];
494*4882a593Smuzhiyun 	u32			rc_label;
495*4882a593Smuzhiyun 	u8			rc_ttl_propagate;
496*4882a593Smuzhiyun 	u8			rc_output_labels;
497*4882a593Smuzhiyun 	u32			rc_output_label[MAX_NEW_LABELS];
498*4882a593Smuzhiyun 	u32			rc_nlflags;
499*4882a593Smuzhiyun 	enum mpls_payload_type	rc_payload_type;
500*4882a593Smuzhiyun 	struct nl_info		rc_nlinfo;
501*4882a593Smuzhiyun 	struct rtnexthop	*rc_mp;
502*4882a593Smuzhiyun 	int			rc_mp_len;
503*4882a593Smuzhiyun };
504*4882a593Smuzhiyun 
505*4882a593Smuzhiyun /* all nexthops within a route have the same size based on max
506*4882a593Smuzhiyun  * number of labels and max via length for a hop
507*4882a593Smuzhiyun  */
mpls_rt_alloc(u8 num_nh,u8 max_alen,u8 max_labels)508*4882a593Smuzhiyun static struct mpls_route *mpls_rt_alloc(u8 num_nh, u8 max_alen, u8 max_labels)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun 	u8 nh_size = MPLS_NH_SIZE(max_labels, max_alen);
511*4882a593Smuzhiyun 	struct mpls_route *rt;
512*4882a593Smuzhiyun 	size_t size;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	size = sizeof(*rt) + num_nh * nh_size;
515*4882a593Smuzhiyun 	if (size > MAX_MPLS_ROUTE_MEM)
516*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 	rt = kzalloc(size, GFP_KERNEL);
519*4882a593Smuzhiyun 	if (!rt)
520*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	rt->rt_nhn = num_nh;
523*4882a593Smuzhiyun 	rt->rt_nhn_alive = num_nh;
524*4882a593Smuzhiyun 	rt->rt_nh_size = nh_size;
525*4882a593Smuzhiyun 	rt->rt_via_offset = MPLS_NH_VIA_OFF(max_labels);
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	return rt;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun 
mpls_rt_free(struct mpls_route * rt)530*4882a593Smuzhiyun static void mpls_rt_free(struct mpls_route *rt)
531*4882a593Smuzhiyun {
532*4882a593Smuzhiyun 	if (rt)
533*4882a593Smuzhiyun 		kfree_rcu(rt, rt_rcu);
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun 
mpls_notify_route(struct net * net,unsigned index,struct mpls_route * old,struct mpls_route * new,const struct nl_info * info)536*4882a593Smuzhiyun static void mpls_notify_route(struct net *net, unsigned index,
537*4882a593Smuzhiyun 			      struct mpls_route *old, struct mpls_route *new,
538*4882a593Smuzhiyun 			      const struct nl_info *info)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	struct nlmsghdr *nlh = info ? info->nlh : NULL;
541*4882a593Smuzhiyun 	unsigned portid = info ? info->portid : 0;
542*4882a593Smuzhiyun 	int event = new ? RTM_NEWROUTE : RTM_DELROUTE;
543*4882a593Smuzhiyun 	struct mpls_route *rt = new ? new : old;
544*4882a593Smuzhiyun 	unsigned nlm_flags = (old && new) ? NLM_F_REPLACE : 0;
545*4882a593Smuzhiyun 	/* Ignore reserved labels for now */
546*4882a593Smuzhiyun 	if (rt && (index >= MPLS_LABEL_FIRST_UNRESERVED))
547*4882a593Smuzhiyun 		rtmsg_lfib(event, index, rt, nlh, net, portid, nlm_flags);
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
mpls_route_update(struct net * net,unsigned index,struct mpls_route * new,const struct nl_info * info)550*4882a593Smuzhiyun static void mpls_route_update(struct net *net, unsigned index,
551*4882a593Smuzhiyun 			      struct mpls_route *new,
552*4882a593Smuzhiyun 			      const struct nl_info *info)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	struct mpls_route __rcu **platform_label;
555*4882a593Smuzhiyun 	struct mpls_route *rt;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	ASSERT_RTNL();
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 	platform_label = rtnl_dereference(net->mpls.platform_label);
560*4882a593Smuzhiyun 	rt = rtnl_dereference(platform_label[index]);
561*4882a593Smuzhiyun 	rcu_assign_pointer(platform_label[index], new);
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	mpls_notify_route(net, index, rt, new, info);
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	/* If we removed a route free it now */
566*4882a593Smuzhiyun 	mpls_rt_free(rt);
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun 
find_free_label(struct net * net)569*4882a593Smuzhiyun static unsigned find_free_label(struct net *net)
570*4882a593Smuzhiyun {
571*4882a593Smuzhiyun 	struct mpls_route __rcu **platform_label;
572*4882a593Smuzhiyun 	size_t platform_labels;
573*4882a593Smuzhiyun 	unsigned index;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	platform_label = rtnl_dereference(net->mpls.platform_label);
576*4882a593Smuzhiyun 	platform_labels = net->mpls.platform_labels;
577*4882a593Smuzhiyun 	for (index = MPLS_LABEL_FIRST_UNRESERVED; index < platform_labels;
578*4882a593Smuzhiyun 	     index++) {
579*4882a593Smuzhiyun 		if (!rtnl_dereference(platform_label[index]))
580*4882a593Smuzhiyun 			return index;
581*4882a593Smuzhiyun 	}
582*4882a593Smuzhiyun 	return LABEL_NOT_SPECIFIED;
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_INET)
inet_fib_lookup_dev(struct net * net,const void * addr)586*4882a593Smuzhiyun static struct net_device *inet_fib_lookup_dev(struct net *net,
587*4882a593Smuzhiyun 					      const void *addr)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	struct net_device *dev;
590*4882a593Smuzhiyun 	struct rtable *rt;
591*4882a593Smuzhiyun 	struct in_addr daddr;
592*4882a593Smuzhiyun 
593*4882a593Smuzhiyun 	memcpy(&daddr, addr, sizeof(struct in_addr));
594*4882a593Smuzhiyun 	rt = ip_route_output(net, daddr.s_addr, 0, 0, 0);
595*4882a593Smuzhiyun 	if (IS_ERR(rt))
596*4882a593Smuzhiyun 		return ERR_CAST(rt);
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	dev = rt->dst.dev;
599*4882a593Smuzhiyun 	dev_hold(dev);
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	ip_rt_put(rt);
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	return dev;
604*4882a593Smuzhiyun }
605*4882a593Smuzhiyun #else
inet_fib_lookup_dev(struct net * net,const void * addr)606*4882a593Smuzhiyun static struct net_device *inet_fib_lookup_dev(struct net *net,
607*4882a593Smuzhiyun 					      const void *addr)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun 	return ERR_PTR(-EAFNOSUPPORT);
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun #endif
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_IPV6)
inet6_fib_lookup_dev(struct net * net,const void * addr)614*4882a593Smuzhiyun static struct net_device *inet6_fib_lookup_dev(struct net *net,
615*4882a593Smuzhiyun 					       const void *addr)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun 	struct net_device *dev;
618*4882a593Smuzhiyun 	struct dst_entry *dst;
619*4882a593Smuzhiyun 	struct flowi6 fl6;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	if (!ipv6_stub)
622*4882a593Smuzhiyun 		return ERR_PTR(-EAFNOSUPPORT);
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	memset(&fl6, 0, sizeof(fl6));
625*4882a593Smuzhiyun 	memcpy(&fl6.daddr, addr, sizeof(struct in6_addr));
626*4882a593Smuzhiyun 	dst = ipv6_stub->ipv6_dst_lookup_flow(net, NULL, &fl6, NULL);
627*4882a593Smuzhiyun 	if (IS_ERR(dst))
628*4882a593Smuzhiyun 		return ERR_CAST(dst);
629*4882a593Smuzhiyun 
630*4882a593Smuzhiyun 	dev = dst->dev;
631*4882a593Smuzhiyun 	dev_hold(dev);
632*4882a593Smuzhiyun 	dst_release(dst);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	return dev;
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun #else
inet6_fib_lookup_dev(struct net * net,const void * addr)637*4882a593Smuzhiyun static struct net_device *inet6_fib_lookup_dev(struct net *net,
638*4882a593Smuzhiyun 					       const void *addr)
639*4882a593Smuzhiyun {
640*4882a593Smuzhiyun 	return ERR_PTR(-EAFNOSUPPORT);
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun #endif
643*4882a593Smuzhiyun 
find_outdev(struct net * net,struct mpls_route * rt,struct mpls_nh * nh,int oif)644*4882a593Smuzhiyun static struct net_device *find_outdev(struct net *net,
645*4882a593Smuzhiyun 				      struct mpls_route *rt,
646*4882a593Smuzhiyun 				      struct mpls_nh *nh, int oif)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun 	struct net_device *dev = NULL;
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	if (!oif) {
651*4882a593Smuzhiyun 		switch (nh->nh_via_table) {
652*4882a593Smuzhiyun 		case NEIGH_ARP_TABLE:
653*4882a593Smuzhiyun 			dev = inet_fib_lookup_dev(net, mpls_nh_via(rt, nh));
654*4882a593Smuzhiyun 			break;
655*4882a593Smuzhiyun 		case NEIGH_ND_TABLE:
656*4882a593Smuzhiyun 			dev = inet6_fib_lookup_dev(net, mpls_nh_via(rt, nh));
657*4882a593Smuzhiyun 			break;
658*4882a593Smuzhiyun 		case NEIGH_LINK_TABLE:
659*4882a593Smuzhiyun 			break;
660*4882a593Smuzhiyun 		}
661*4882a593Smuzhiyun 	} else {
662*4882a593Smuzhiyun 		dev = dev_get_by_index(net, oif);
663*4882a593Smuzhiyun 	}
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 	if (!dev)
666*4882a593Smuzhiyun 		return ERR_PTR(-ENODEV);
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	if (IS_ERR(dev))
669*4882a593Smuzhiyun 		return dev;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	/* The caller is holding rtnl anyways, so release the dev reference */
672*4882a593Smuzhiyun 	dev_put(dev);
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	return dev;
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun 
mpls_nh_assign_dev(struct net * net,struct mpls_route * rt,struct mpls_nh * nh,int oif)677*4882a593Smuzhiyun static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
678*4882a593Smuzhiyun 			      struct mpls_nh *nh, int oif)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	struct net_device *dev = NULL;
681*4882a593Smuzhiyun 	int err = -ENODEV;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	dev = find_outdev(net, rt, nh, oif);
684*4882a593Smuzhiyun 	if (IS_ERR(dev)) {
685*4882a593Smuzhiyun 		err = PTR_ERR(dev);
686*4882a593Smuzhiyun 		dev = NULL;
687*4882a593Smuzhiyun 		goto errout;
688*4882a593Smuzhiyun 	}
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun 	/* Ensure this is a supported device */
691*4882a593Smuzhiyun 	err = -EINVAL;
692*4882a593Smuzhiyun 	if (!mpls_dev_get(dev))
693*4882a593Smuzhiyun 		goto errout;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	if ((nh->nh_via_table == NEIGH_LINK_TABLE) &&
696*4882a593Smuzhiyun 	    (dev->addr_len != nh->nh_via_alen))
697*4882a593Smuzhiyun 		goto errout;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	RCU_INIT_POINTER(nh->nh_dev, dev);
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	if (!(dev->flags & IFF_UP)) {
702*4882a593Smuzhiyun 		nh->nh_flags |= RTNH_F_DEAD;
703*4882a593Smuzhiyun 	} else {
704*4882a593Smuzhiyun 		unsigned int flags;
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun 		flags = dev_get_flags(dev);
707*4882a593Smuzhiyun 		if (!(flags & (IFF_RUNNING | IFF_LOWER_UP)))
708*4882a593Smuzhiyun 			nh->nh_flags |= RTNH_F_LINKDOWN;
709*4882a593Smuzhiyun 	}
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	return 0;
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun errout:
714*4882a593Smuzhiyun 	return err;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun 
nla_get_via(const struct nlattr * nla,u8 * via_alen,u8 * via_table,u8 via_addr[],struct netlink_ext_ack * extack)717*4882a593Smuzhiyun static int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
718*4882a593Smuzhiyun 		       u8 via_addr[], struct netlink_ext_ack *extack)
719*4882a593Smuzhiyun {
720*4882a593Smuzhiyun 	struct rtvia *via = nla_data(nla);
721*4882a593Smuzhiyun 	int err = -EINVAL;
722*4882a593Smuzhiyun 	int alen;
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr)) {
725*4882a593Smuzhiyun 		NL_SET_ERR_MSG_ATTR(extack, nla,
726*4882a593Smuzhiyun 				    "Invalid attribute length for RTA_VIA");
727*4882a593Smuzhiyun 		goto errout;
728*4882a593Smuzhiyun 	}
729*4882a593Smuzhiyun 	alen = nla_len(nla) -
730*4882a593Smuzhiyun 			offsetof(struct rtvia, rtvia_addr);
731*4882a593Smuzhiyun 	if (alen > MAX_VIA_ALEN) {
732*4882a593Smuzhiyun 		NL_SET_ERR_MSG_ATTR(extack, nla,
733*4882a593Smuzhiyun 				    "Invalid address length for RTA_VIA");
734*4882a593Smuzhiyun 		goto errout;
735*4882a593Smuzhiyun 	}
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	/* Validate the address family */
738*4882a593Smuzhiyun 	switch (via->rtvia_family) {
739*4882a593Smuzhiyun 	case AF_PACKET:
740*4882a593Smuzhiyun 		*via_table = NEIGH_LINK_TABLE;
741*4882a593Smuzhiyun 		break;
742*4882a593Smuzhiyun 	case AF_INET:
743*4882a593Smuzhiyun 		*via_table = NEIGH_ARP_TABLE;
744*4882a593Smuzhiyun 		if (alen != 4)
745*4882a593Smuzhiyun 			goto errout;
746*4882a593Smuzhiyun 		break;
747*4882a593Smuzhiyun 	case AF_INET6:
748*4882a593Smuzhiyun 		*via_table = NEIGH_ND_TABLE;
749*4882a593Smuzhiyun 		if (alen != 16)
750*4882a593Smuzhiyun 			goto errout;
751*4882a593Smuzhiyun 		break;
752*4882a593Smuzhiyun 	default:
753*4882a593Smuzhiyun 		/* Unsupported address family */
754*4882a593Smuzhiyun 		goto errout;
755*4882a593Smuzhiyun 	}
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	memcpy(via_addr, via->rtvia_addr, alen);
758*4882a593Smuzhiyun 	*via_alen = alen;
759*4882a593Smuzhiyun 	err = 0;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun errout:
762*4882a593Smuzhiyun 	return err;
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun 
mpls_nh_build_from_cfg(struct mpls_route_config * cfg,struct mpls_route * rt)765*4882a593Smuzhiyun static int mpls_nh_build_from_cfg(struct mpls_route_config *cfg,
766*4882a593Smuzhiyun 				  struct mpls_route *rt)
767*4882a593Smuzhiyun {
768*4882a593Smuzhiyun 	struct net *net = cfg->rc_nlinfo.nl_net;
769*4882a593Smuzhiyun 	struct mpls_nh *nh = rt->rt_nh;
770*4882a593Smuzhiyun 	int err;
771*4882a593Smuzhiyun 	int i;
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun 	if (!nh)
774*4882a593Smuzhiyun 		return -ENOMEM;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	nh->nh_labels = cfg->rc_output_labels;
777*4882a593Smuzhiyun 	for (i = 0; i < nh->nh_labels; i++)
778*4882a593Smuzhiyun 		nh->nh_label[i] = cfg->rc_output_label[i];
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	nh->nh_via_table = cfg->rc_via_table;
781*4882a593Smuzhiyun 	memcpy(__mpls_nh_via(rt, nh), cfg->rc_via, cfg->rc_via_alen);
782*4882a593Smuzhiyun 	nh->nh_via_alen = cfg->rc_via_alen;
783*4882a593Smuzhiyun 
784*4882a593Smuzhiyun 	err = mpls_nh_assign_dev(net, rt, nh, cfg->rc_ifindex);
785*4882a593Smuzhiyun 	if (err)
786*4882a593Smuzhiyun 		goto errout;
787*4882a593Smuzhiyun 
788*4882a593Smuzhiyun 	if (nh->nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN))
789*4882a593Smuzhiyun 		rt->rt_nhn_alive--;
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun 	return 0;
792*4882a593Smuzhiyun 
793*4882a593Smuzhiyun errout:
794*4882a593Smuzhiyun 	return err;
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun 
mpls_nh_build(struct net * net,struct mpls_route * rt,struct mpls_nh * nh,int oif,struct nlattr * via,struct nlattr * newdst,u8 max_labels,struct netlink_ext_ack * extack)797*4882a593Smuzhiyun static int mpls_nh_build(struct net *net, struct mpls_route *rt,
798*4882a593Smuzhiyun 			 struct mpls_nh *nh, int oif, struct nlattr *via,
799*4882a593Smuzhiyun 			 struct nlattr *newdst, u8 max_labels,
800*4882a593Smuzhiyun 			 struct netlink_ext_ack *extack)
801*4882a593Smuzhiyun {
802*4882a593Smuzhiyun 	int err = -ENOMEM;
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun 	if (!nh)
805*4882a593Smuzhiyun 		goto errout;
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 	if (newdst) {
808*4882a593Smuzhiyun 		err = nla_get_labels(newdst, max_labels, &nh->nh_labels,
809*4882a593Smuzhiyun 				     nh->nh_label, extack);
810*4882a593Smuzhiyun 		if (err)
811*4882a593Smuzhiyun 			goto errout;
812*4882a593Smuzhiyun 	}
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 	if (via) {
815*4882a593Smuzhiyun 		err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table,
816*4882a593Smuzhiyun 				  __mpls_nh_via(rt, nh), extack);
817*4882a593Smuzhiyun 		if (err)
818*4882a593Smuzhiyun 			goto errout;
819*4882a593Smuzhiyun 	} else {
820*4882a593Smuzhiyun 		nh->nh_via_table = MPLS_NEIGH_TABLE_UNSPEC;
821*4882a593Smuzhiyun 	}
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 	err = mpls_nh_assign_dev(net, rt, nh, oif);
824*4882a593Smuzhiyun 	if (err)
825*4882a593Smuzhiyun 		goto errout;
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	return 0;
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun errout:
830*4882a593Smuzhiyun 	return err;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun 
mpls_count_nexthops(struct rtnexthop * rtnh,int len,u8 cfg_via_alen,u8 * max_via_alen,u8 * max_labels)833*4882a593Smuzhiyun static u8 mpls_count_nexthops(struct rtnexthop *rtnh, int len,
834*4882a593Smuzhiyun 			      u8 cfg_via_alen, u8 *max_via_alen,
835*4882a593Smuzhiyun 			      u8 *max_labels)
836*4882a593Smuzhiyun {
837*4882a593Smuzhiyun 	int remaining = len;
838*4882a593Smuzhiyun 	u8 nhs = 0;
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 	*max_via_alen = 0;
841*4882a593Smuzhiyun 	*max_labels = 0;
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 	while (rtnh_ok(rtnh, remaining)) {
844*4882a593Smuzhiyun 		struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
845*4882a593Smuzhiyun 		int attrlen;
846*4882a593Smuzhiyun 		u8 n_labels = 0;
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun 		attrlen = rtnh_attrlen(rtnh);
849*4882a593Smuzhiyun 		nla = nla_find(attrs, attrlen, RTA_VIA);
850*4882a593Smuzhiyun 		if (nla && nla_len(nla) >=
851*4882a593Smuzhiyun 		    offsetof(struct rtvia, rtvia_addr)) {
852*4882a593Smuzhiyun 			int via_alen = nla_len(nla) -
853*4882a593Smuzhiyun 				offsetof(struct rtvia, rtvia_addr);
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 			if (via_alen <= MAX_VIA_ALEN)
856*4882a593Smuzhiyun 				*max_via_alen = max_t(u16, *max_via_alen,
857*4882a593Smuzhiyun 						      via_alen);
858*4882a593Smuzhiyun 		}
859*4882a593Smuzhiyun 
860*4882a593Smuzhiyun 		nla = nla_find(attrs, attrlen, RTA_NEWDST);
861*4882a593Smuzhiyun 		if (nla &&
862*4882a593Smuzhiyun 		    nla_get_labels(nla, MAX_NEW_LABELS, &n_labels,
863*4882a593Smuzhiyun 				   NULL, NULL) != 0)
864*4882a593Smuzhiyun 			return 0;
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 		*max_labels = max_t(u8, *max_labels, n_labels);
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 		/* number of nexthops is tracked by a u8.
869*4882a593Smuzhiyun 		 * Check for overflow.
870*4882a593Smuzhiyun 		 */
871*4882a593Smuzhiyun 		if (nhs == 255)
872*4882a593Smuzhiyun 			return 0;
873*4882a593Smuzhiyun 		nhs++;
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 		rtnh = rtnh_next(rtnh, &remaining);
876*4882a593Smuzhiyun 	}
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 	/* leftover implies invalid nexthop configuration, discard it */
879*4882a593Smuzhiyun 	return remaining > 0 ? 0 : nhs;
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun 
mpls_nh_build_multi(struct mpls_route_config * cfg,struct mpls_route * rt,u8 max_labels,struct netlink_ext_ack * extack)882*4882a593Smuzhiyun static int mpls_nh_build_multi(struct mpls_route_config *cfg,
883*4882a593Smuzhiyun 			       struct mpls_route *rt, u8 max_labels,
884*4882a593Smuzhiyun 			       struct netlink_ext_ack *extack)
885*4882a593Smuzhiyun {
886*4882a593Smuzhiyun 	struct rtnexthop *rtnh = cfg->rc_mp;
887*4882a593Smuzhiyun 	struct nlattr *nla_via, *nla_newdst;
888*4882a593Smuzhiyun 	int remaining = cfg->rc_mp_len;
889*4882a593Smuzhiyun 	int err = 0;
890*4882a593Smuzhiyun 	u8 nhs = 0;
891*4882a593Smuzhiyun 
892*4882a593Smuzhiyun 	change_nexthops(rt) {
893*4882a593Smuzhiyun 		int attrlen;
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 		nla_via = NULL;
896*4882a593Smuzhiyun 		nla_newdst = NULL;
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 		err = -EINVAL;
899*4882a593Smuzhiyun 		if (!rtnh_ok(rtnh, remaining))
900*4882a593Smuzhiyun 			goto errout;
901*4882a593Smuzhiyun 
902*4882a593Smuzhiyun 		/* neither weighted multipath nor any flags
903*4882a593Smuzhiyun 		 * are supported
904*4882a593Smuzhiyun 		 */
905*4882a593Smuzhiyun 		if (rtnh->rtnh_hops || rtnh->rtnh_flags)
906*4882a593Smuzhiyun 			goto errout;
907*4882a593Smuzhiyun 
908*4882a593Smuzhiyun 		attrlen = rtnh_attrlen(rtnh);
909*4882a593Smuzhiyun 		if (attrlen > 0) {
910*4882a593Smuzhiyun 			struct nlattr *attrs = rtnh_attrs(rtnh);
911*4882a593Smuzhiyun 
912*4882a593Smuzhiyun 			nla_via = nla_find(attrs, attrlen, RTA_VIA);
913*4882a593Smuzhiyun 			nla_newdst = nla_find(attrs, attrlen, RTA_NEWDST);
914*4882a593Smuzhiyun 		}
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun 		err = mpls_nh_build(cfg->rc_nlinfo.nl_net, rt, nh,
917*4882a593Smuzhiyun 				    rtnh->rtnh_ifindex, nla_via, nla_newdst,
918*4882a593Smuzhiyun 				    max_labels, extack);
919*4882a593Smuzhiyun 		if (err)
920*4882a593Smuzhiyun 			goto errout;
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 		if (nh->nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN))
923*4882a593Smuzhiyun 			rt->rt_nhn_alive--;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 		rtnh = rtnh_next(rtnh, &remaining);
926*4882a593Smuzhiyun 		nhs++;
927*4882a593Smuzhiyun 	} endfor_nexthops(rt);
928*4882a593Smuzhiyun 
929*4882a593Smuzhiyun 	rt->rt_nhn = nhs;
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	return 0;
932*4882a593Smuzhiyun 
933*4882a593Smuzhiyun errout:
934*4882a593Smuzhiyun 	return err;
935*4882a593Smuzhiyun }
936*4882a593Smuzhiyun 
mpls_label_ok(struct net * net,unsigned int * index,struct netlink_ext_ack * extack)937*4882a593Smuzhiyun static bool mpls_label_ok(struct net *net, unsigned int *index,
938*4882a593Smuzhiyun 			  struct netlink_ext_ack *extack)
939*4882a593Smuzhiyun {
940*4882a593Smuzhiyun 	bool is_ok = true;
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	/* Reserved labels may not be set */
943*4882a593Smuzhiyun 	if (*index < MPLS_LABEL_FIRST_UNRESERVED) {
944*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack,
945*4882a593Smuzhiyun 			       "Invalid label - must be MPLS_LABEL_FIRST_UNRESERVED or higher");
946*4882a593Smuzhiyun 		is_ok = false;
947*4882a593Smuzhiyun 	}
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun 	/* The full 20 bit range may not be supported. */
950*4882a593Smuzhiyun 	if (is_ok && *index >= net->mpls.platform_labels) {
951*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack,
952*4882a593Smuzhiyun 			       "Label >= configured maximum in platform_labels");
953*4882a593Smuzhiyun 		is_ok = false;
954*4882a593Smuzhiyun 	}
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun 	*index = array_index_nospec(*index, net->mpls.platform_labels);
957*4882a593Smuzhiyun 	return is_ok;
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun 
mpls_route_add(struct mpls_route_config * cfg,struct netlink_ext_ack * extack)960*4882a593Smuzhiyun static int mpls_route_add(struct mpls_route_config *cfg,
961*4882a593Smuzhiyun 			  struct netlink_ext_ack *extack)
962*4882a593Smuzhiyun {
963*4882a593Smuzhiyun 	struct mpls_route __rcu **platform_label;
964*4882a593Smuzhiyun 	struct net *net = cfg->rc_nlinfo.nl_net;
965*4882a593Smuzhiyun 	struct mpls_route *rt, *old;
966*4882a593Smuzhiyun 	int err = -EINVAL;
967*4882a593Smuzhiyun 	u8 max_via_alen;
968*4882a593Smuzhiyun 	unsigned index;
969*4882a593Smuzhiyun 	u8 max_labels;
970*4882a593Smuzhiyun 	u8 nhs;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	index = cfg->rc_label;
973*4882a593Smuzhiyun 
974*4882a593Smuzhiyun 	/* If a label was not specified during insert pick one */
975*4882a593Smuzhiyun 	if ((index == LABEL_NOT_SPECIFIED) &&
976*4882a593Smuzhiyun 	    (cfg->rc_nlflags & NLM_F_CREATE)) {
977*4882a593Smuzhiyun 		index = find_free_label(net);
978*4882a593Smuzhiyun 	}
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 	if (!mpls_label_ok(net, &index, extack))
981*4882a593Smuzhiyun 		goto errout;
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	/* Append makes no sense with mpls */
984*4882a593Smuzhiyun 	err = -EOPNOTSUPP;
985*4882a593Smuzhiyun 	if (cfg->rc_nlflags & NLM_F_APPEND) {
986*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "MPLS does not support route append");
987*4882a593Smuzhiyun 		goto errout;
988*4882a593Smuzhiyun 	}
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	err = -EEXIST;
991*4882a593Smuzhiyun 	platform_label = rtnl_dereference(net->mpls.platform_label);
992*4882a593Smuzhiyun 	old = rtnl_dereference(platform_label[index]);
993*4882a593Smuzhiyun 	if ((cfg->rc_nlflags & NLM_F_EXCL) && old)
994*4882a593Smuzhiyun 		goto errout;
995*4882a593Smuzhiyun 
996*4882a593Smuzhiyun 	err = -EEXIST;
997*4882a593Smuzhiyun 	if (!(cfg->rc_nlflags & NLM_F_REPLACE) && old)
998*4882a593Smuzhiyun 		goto errout;
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun 	err = -ENOENT;
1001*4882a593Smuzhiyun 	if (!(cfg->rc_nlflags & NLM_F_CREATE) && !old)
1002*4882a593Smuzhiyun 		goto errout;
1003*4882a593Smuzhiyun 
1004*4882a593Smuzhiyun 	err = -EINVAL;
1005*4882a593Smuzhiyun 	if (cfg->rc_mp) {
1006*4882a593Smuzhiyun 		nhs = mpls_count_nexthops(cfg->rc_mp, cfg->rc_mp_len,
1007*4882a593Smuzhiyun 					  cfg->rc_via_alen, &max_via_alen,
1008*4882a593Smuzhiyun 					  &max_labels);
1009*4882a593Smuzhiyun 	} else {
1010*4882a593Smuzhiyun 		max_via_alen = cfg->rc_via_alen;
1011*4882a593Smuzhiyun 		max_labels = cfg->rc_output_labels;
1012*4882a593Smuzhiyun 		nhs = 1;
1013*4882a593Smuzhiyun 	}
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun 	if (nhs == 0) {
1016*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Route does not contain a nexthop");
1017*4882a593Smuzhiyun 		goto errout;
1018*4882a593Smuzhiyun 	}
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun 	err = -ENOMEM;
1021*4882a593Smuzhiyun 	rt = mpls_rt_alloc(nhs, max_via_alen, max_labels);
1022*4882a593Smuzhiyun 	if (IS_ERR(rt)) {
1023*4882a593Smuzhiyun 		err = PTR_ERR(rt);
1024*4882a593Smuzhiyun 		goto errout;
1025*4882a593Smuzhiyun 	}
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun 	rt->rt_protocol = cfg->rc_protocol;
1028*4882a593Smuzhiyun 	rt->rt_payload_type = cfg->rc_payload_type;
1029*4882a593Smuzhiyun 	rt->rt_ttl_propagate = cfg->rc_ttl_propagate;
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	if (cfg->rc_mp)
1032*4882a593Smuzhiyun 		err = mpls_nh_build_multi(cfg, rt, max_labels, extack);
1033*4882a593Smuzhiyun 	else
1034*4882a593Smuzhiyun 		err = mpls_nh_build_from_cfg(cfg, rt);
1035*4882a593Smuzhiyun 	if (err)
1036*4882a593Smuzhiyun 		goto freert;
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 	mpls_route_update(net, index, rt, &cfg->rc_nlinfo);
1039*4882a593Smuzhiyun 
1040*4882a593Smuzhiyun 	return 0;
1041*4882a593Smuzhiyun 
1042*4882a593Smuzhiyun freert:
1043*4882a593Smuzhiyun 	mpls_rt_free(rt);
1044*4882a593Smuzhiyun errout:
1045*4882a593Smuzhiyun 	return err;
1046*4882a593Smuzhiyun }
1047*4882a593Smuzhiyun 
mpls_route_del(struct mpls_route_config * cfg,struct netlink_ext_ack * extack)1048*4882a593Smuzhiyun static int mpls_route_del(struct mpls_route_config *cfg,
1049*4882a593Smuzhiyun 			  struct netlink_ext_ack *extack)
1050*4882a593Smuzhiyun {
1051*4882a593Smuzhiyun 	struct net *net = cfg->rc_nlinfo.nl_net;
1052*4882a593Smuzhiyun 	unsigned index;
1053*4882a593Smuzhiyun 	int err = -EINVAL;
1054*4882a593Smuzhiyun 
1055*4882a593Smuzhiyun 	index = cfg->rc_label;
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 	if (!mpls_label_ok(net, &index, extack))
1058*4882a593Smuzhiyun 		goto errout;
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	mpls_route_update(net, index, NULL, &cfg->rc_nlinfo);
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun 	err = 0;
1063*4882a593Smuzhiyun errout:
1064*4882a593Smuzhiyun 	return err;
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun 
mpls_get_stats(struct mpls_dev * mdev,struct mpls_link_stats * stats)1067*4882a593Smuzhiyun static void mpls_get_stats(struct mpls_dev *mdev,
1068*4882a593Smuzhiyun 			   struct mpls_link_stats *stats)
1069*4882a593Smuzhiyun {
1070*4882a593Smuzhiyun 	struct mpls_pcpu_stats *p;
1071*4882a593Smuzhiyun 	int i;
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun 	memset(stats, 0, sizeof(*stats));
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun 	for_each_possible_cpu(i) {
1076*4882a593Smuzhiyun 		struct mpls_link_stats local;
1077*4882a593Smuzhiyun 		unsigned int start;
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 		p = per_cpu_ptr(mdev->stats, i);
1080*4882a593Smuzhiyun 		do {
1081*4882a593Smuzhiyun 			start = u64_stats_fetch_begin_irq(&p->syncp);
1082*4882a593Smuzhiyun 			local = p->stats;
1083*4882a593Smuzhiyun 		} while (u64_stats_fetch_retry_irq(&p->syncp, start));
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun 		stats->rx_packets	+= local.rx_packets;
1086*4882a593Smuzhiyun 		stats->rx_bytes		+= local.rx_bytes;
1087*4882a593Smuzhiyun 		stats->tx_packets	+= local.tx_packets;
1088*4882a593Smuzhiyun 		stats->tx_bytes		+= local.tx_bytes;
1089*4882a593Smuzhiyun 		stats->rx_errors	+= local.rx_errors;
1090*4882a593Smuzhiyun 		stats->tx_errors	+= local.tx_errors;
1091*4882a593Smuzhiyun 		stats->rx_dropped	+= local.rx_dropped;
1092*4882a593Smuzhiyun 		stats->tx_dropped	+= local.tx_dropped;
1093*4882a593Smuzhiyun 		stats->rx_noroute	+= local.rx_noroute;
1094*4882a593Smuzhiyun 	}
1095*4882a593Smuzhiyun }
1096*4882a593Smuzhiyun 
mpls_fill_stats_af(struct sk_buff * skb,const struct net_device * dev)1097*4882a593Smuzhiyun static int mpls_fill_stats_af(struct sk_buff *skb,
1098*4882a593Smuzhiyun 			      const struct net_device *dev)
1099*4882a593Smuzhiyun {
1100*4882a593Smuzhiyun 	struct mpls_link_stats *stats;
1101*4882a593Smuzhiyun 	struct mpls_dev *mdev;
1102*4882a593Smuzhiyun 	struct nlattr *nla;
1103*4882a593Smuzhiyun 
1104*4882a593Smuzhiyun 	mdev = mpls_dev_get(dev);
1105*4882a593Smuzhiyun 	if (!mdev)
1106*4882a593Smuzhiyun 		return -ENODATA;
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	nla = nla_reserve_64bit(skb, MPLS_STATS_LINK,
1109*4882a593Smuzhiyun 				sizeof(struct mpls_link_stats),
1110*4882a593Smuzhiyun 				MPLS_STATS_UNSPEC);
1111*4882a593Smuzhiyun 	if (!nla)
1112*4882a593Smuzhiyun 		return -EMSGSIZE;
1113*4882a593Smuzhiyun 
1114*4882a593Smuzhiyun 	stats = nla_data(nla);
1115*4882a593Smuzhiyun 	mpls_get_stats(mdev, stats);
1116*4882a593Smuzhiyun 
1117*4882a593Smuzhiyun 	return 0;
1118*4882a593Smuzhiyun }
1119*4882a593Smuzhiyun 
mpls_get_stats_af_size(const struct net_device * dev)1120*4882a593Smuzhiyun static size_t mpls_get_stats_af_size(const struct net_device *dev)
1121*4882a593Smuzhiyun {
1122*4882a593Smuzhiyun 	struct mpls_dev *mdev;
1123*4882a593Smuzhiyun 
1124*4882a593Smuzhiyun 	mdev = mpls_dev_get(dev);
1125*4882a593Smuzhiyun 	if (!mdev)
1126*4882a593Smuzhiyun 		return 0;
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun 	return nla_total_size_64bit(sizeof(struct mpls_link_stats));
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun 
mpls_netconf_fill_devconf(struct sk_buff * skb,struct mpls_dev * mdev,u32 portid,u32 seq,int event,unsigned int flags,int type)1131*4882a593Smuzhiyun static int mpls_netconf_fill_devconf(struct sk_buff *skb, struct mpls_dev *mdev,
1132*4882a593Smuzhiyun 				     u32 portid, u32 seq, int event,
1133*4882a593Smuzhiyun 				     unsigned int flags, int type)
1134*4882a593Smuzhiyun {
1135*4882a593Smuzhiyun 	struct nlmsghdr  *nlh;
1136*4882a593Smuzhiyun 	struct netconfmsg *ncm;
1137*4882a593Smuzhiyun 	bool all = false;
1138*4882a593Smuzhiyun 
1139*4882a593Smuzhiyun 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg),
1140*4882a593Smuzhiyun 			flags);
1141*4882a593Smuzhiyun 	if (!nlh)
1142*4882a593Smuzhiyun 		return -EMSGSIZE;
1143*4882a593Smuzhiyun 
1144*4882a593Smuzhiyun 	if (type == NETCONFA_ALL)
1145*4882a593Smuzhiyun 		all = true;
1146*4882a593Smuzhiyun 
1147*4882a593Smuzhiyun 	ncm = nlmsg_data(nlh);
1148*4882a593Smuzhiyun 	ncm->ncm_family = AF_MPLS;
1149*4882a593Smuzhiyun 
1150*4882a593Smuzhiyun 	if (nla_put_s32(skb, NETCONFA_IFINDEX, mdev->dev->ifindex) < 0)
1151*4882a593Smuzhiyun 		goto nla_put_failure;
1152*4882a593Smuzhiyun 
1153*4882a593Smuzhiyun 	if ((all || type == NETCONFA_INPUT) &&
1154*4882a593Smuzhiyun 	    nla_put_s32(skb, NETCONFA_INPUT,
1155*4882a593Smuzhiyun 			mdev->input_enabled) < 0)
1156*4882a593Smuzhiyun 		goto nla_put_failure;
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun 	nlmsg_end(skb, nlh);
1159*4882a593Smuzhiyun 	return 0;
1160*4882a593Smuzhiyun 
1161*4882a593Smuzhiyun nla_put_failure:
1162*4882a593Smuzhiyun 	nlmsg_cancel(skb, nlh);
1163*4882a593Smuzhiyun 	return -EMSGSIZE;
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun 
mpls_netconf_msgsize_devconf(int type)1166*4882a593Smuzhiyun static int mpls_netconf_msgsize_devconf(int type)
1167*4882a593Smuzhiyun {
1168*4882a593Smuzhiyun 	int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
1169*4882a593Smuzhiyun 			+ nla_total_size(4); /* NETCONFA_IFINDEX */
1170*4882a593Smuzhiyun 	bool all = false;
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun 	if (type == NETCONFA_ALL)
1173*4882a593Smuzhiyun 		all = true;
1174*4882a593Smuzhiyun 
1175*4882a593Smuzhiyun 	if (all || type == NETCONFA_INPUT)
1176*4882a593Smuzhiyun 		size += nla_total_size(4);
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	return size;
1179*4882a593Smuzhiyun }
1180*4882a593Smuzhiyun 
mpls_netconf_notify_devconf(struct net * net,int event,int type,struct mpls_dev * mdev)1181*4882a593Smuzhiyun static void mpls_netconf_notify_devconf(struct net *net, int event,
1182*4882a593Smuzhiyun 					int type, struct mpls_dev *mdev)
1183*4882a593Smuzhiyun {
1184*4882a593Smuzhiyun 	struct sk_buff *skb;
1185*4882a593Smuzhiyun 	int err = -ENOBUFS;
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 	skb = nlmsg_new(mpls_netconf_msgsize_devconf(type), GFP_KERNEL);
1188*4882a593Smuzhiyun 	if (!skb)
1189*4882a593Smuzhiyun 		goto errout;
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 	err = mpls_netconf_fill_devconf(skb, mdev, 0, 0, event, 0, type);
1192*4882a593Smuzhiyun 	if (err < 0) {
1193*4882a593Smuzhiyun 		/* -EMSGSIZE implies BUG in mpls_netconf_msgsize_devconf() */
1194*4882a593Smuzhiyun 		WARN_ON(err == -EMSGSIZE);
1195*4882a593Smuzhiyun 		kfree_skb(skb);
1196*4882a593Smuzhiyun 		goto errout;
1197*4882a593Smuzhiyun 	}
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun 	rtnl_notify(skb, net, 0, RTNLGRP_MPLS_NETCONF, NULL, GFP_KERNEL);
1200*4882a593Smuzhiyun 	return;
1201*4882a593Smuzhiyun errout:
1202*4882a593Smuzhiyun 	if (err < 0)
1203*4882a593Smuzhiyun 		rtnl_set_sk_err(net, RTNLGRP_MPLS_NETCONF, err);
1204*4882a593Smuzhiyun }
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun static const struct nla_policy devconf_mpls_policy[NETCONFA_MAX + 1] = {
1207*4882a593Smuzhiyun 	[NETCONFA_IFINDEX]	= { .len = sizeof(int) },
1208*4882a593Smuzhiyun };
1209*4882a593Smuzhiyun 
mpls_netconf_valid_get_req(struct sk_buff * skb,const struct nlmsghdr * nlh,struct nlattr ** tb,struct netlink_ext_ack * extack)1210*4882a593Smuzhiyun static int mpls_netconf_valid_get_req(struct sk_buff *skb,
1211*4882a593Smuzhiyun 				      const struct nlmsghdr *nlh,
1212*4882a593Smuzhiyun 				      struct nlattr **tb,
1213*4882a593Smuzhiyun 				      struct netlink_ext_ack *extack)
1214*4882a593Smuzhiyun {
1215*4882a593Smuzhiyun 	int i, err;
1216*4882a593Smuzhiyun 
1217*4882a593Smuzhiyun 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(struct netconfmsg))) {
1218*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack,
1219*4882a593Smuzhiyun 				   "Invalid header for netconf get request");
1220*4882a593Smuzhiyun 		return -EINVAL;
1221*4882a593Smuzhiyun 	}
1222*4882a593Smuzhiyun 
1223*4882a593Smuzhiyun 	if (!netlink_strict_get_check(skb))
1224*4882a593Smuzhiyun 		return nlmsg_parse_deprecated(nlh, sizeof(struct netconfmsg),
1225*4882a593Smuzhiyun 					      tb, NETCONFA_MAX,
1226*4882a593Smuzhiyun 					      devconf_mpls_policy, extack);
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 	err = nlmsg_parse_deprecated_strict(nlh, sizeof(struct netconfmsg),
1229*4882a593Smuzhiyun 					    tb, NETCONFA_MAX,
1230*4882a593Smuzhiyun 					    devconf_mpls_policy, extack);
1231*4882a593Smuzhiyun 	if (err)
1232*4882a593Smuzhiyun 		return err;
1233*4882a593Smuzhiyun 
1234*4882a593Smuzhiyun 	for (i = 0; i <= NETCONFA_MAX; i++) {
1235*4882a593Smuzhiyun 		if (!tb[i])
1236*4882a593Smuzhiyun 			continue;
1237*4882a593Smuzhiyun 
1238*4882a593Smuzhiyun 		switch (i) {
1239*4882a593Smuzhiyun 		case NETCONFA_IFINDEX:
1240*4882a593Smuzhiyun 			break;
1241*4882a593Smuzhiyun 		default:
1242*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in netconf get request");
1243*4882a593Smuzhiyun 			return -EINVAL;
1244*4882a593Smuzhiyun 		}
1245*4882a593Smuzhiyun 	}
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun 	return 0;
1248*4882a593Smuzhiyun }
1249*4882a593Smuzhiyun 
mpls_netconf_get_devconf(struct sk_buff * in_skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)1250*4882a593Smuzhiyun static int mpls_netconf_get_devconf(struct sk_buff *in_skb,
1251*4882a593Smuzhiyun 				    struct nlmsghdr *nlh,
1252*4882a593Smuzhiyun 				    struct netlink_ext_ack *extack)
1253*4882a593Smuzhiyun {
1254*4882a593Smuzhiyun 	struct net *net = sock_net(in_skb->sk);
1255*4882a593Smuzhiyun 	struct nlattr *tb[NETCONFA_MAX + 1];
1256*4882a593Smuzhiyun 	struct net_device *dev;
1257*4882a593Smuzhiyun 	struct mpls_dev *mdev;
1258*4882a593Smuzhiyun 	struct sk_buff *skb;
1259*4882a593Smuzhiyun 	int ifindex;
1260*4882a593Smuzhiyun 	int err;
1261*4882a593Smuzhiyun 
1262*4882a593Smuzhiyun 	err = mpls_netconf_valid_get_req(in_skb, nlh, tb, extack);
1263*4882a593Smuzhiyun 	if (err < 0)
1264*4882a593Smuzhiyun 		goto errout;
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun 	err = -EINVAL;
1267*4882a593Smuzhiyun 	if (!tb[NETCONFA_IFINDEX])
1268*4882a593Smuzhiyun 		goto errout;
1269*4882a593Smuzhiyun 
1270*4882a593Smuzhiyun 	ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
1271*4882a593Smuzhiyun 	dev = __dev_get_by_index(net, ifindex);
1272*4882a593Smuzhiyun 	if (!dev)
1273*4882a593Smuzhiyun 		goto errout;
1274*4882a593Smuzhiyun 
1275*4882a593Smuzhiyun 	mdev = mpls_dev_get(dev);
1276*4882a593Smuzhiyun 	if (!mdev)
1277*4882a593Smuzhiyun 		goto errout;
1278*4882a593Smuzhiyun 
1279*4882a593Smuzhiyun 	err = -ENOBUFS;
1280*4882a593Smuzhiyun 	skb = nlmsg_new(mpls_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL);
1281*4882a593Smuzhiyun 	if (!skb)
1282*4882a593Smuzhiyun 		goto errout;
1283*4882a593Smuzhiyun 
1284*4882a593Smuzhiyun 	err = mpls_netconf_fill_devconf(skb, mdev,
1285*4882a593Smuzhiyun 					NETLINK_CB(in_skb).portid,
1286*4882a593Smuzhiyun 					nlh->nlmsg_seq, RTM_NEWNETCONF, 0,
1287*4882a593Smuzhiyun 					NETCONFA_ALL);
1288*4882a593Smuzhiyun 	if (err < 0) {
1289*4882a593Smuzhiyun 		/* -EMSGSIZE implies BUG in mpls_netconf_msgsize_devconf() */
1290*4882a593Smuzhiyun 		WARN_ON(err == -EMSGSIZE);
1291*4882a593Smuzhiyun 		kfree_skb(skb);
1292*4882a593Smuzhiyun 		goto errout;
1293*4882a593Smuzhiyun 	}
1294*4882a593Smuzhiyun 	err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid);
1295*4882a593Smuzhiyun errout:
1296*4882a593Smuzhiyun 	return err;
1297*4882a593Smuzhiyun }
1298*4882a593Smuzhiyun 
mpls_netconf_dump_devconf(struct sk_buff * skb,struct netlink_callback * cb)1299*4882a593Smuzhiyun static int mpls_netconf_dump_devconf(struct sk_buff *skb,
1300*4882a593Smuzhiyun 				     struct netlink_callback *cb)
1301*4882a593Smuzhiyun {
1302*4882a593Smuzhiyun 	const struct nlmsghdr *nlh = cb->nlh;
1303*4882a593Smuzhiyun 	struct net *net = sock_net(skb->sk);
1304*4882a593Smuzhiyun 	struct hlist_head *head;
1305*4882a593Smuzhiyun 	struct net_device *dev;
1306*4882a593Smuzhiyun 	struct mpls_dev *mdev;
1307*4882a593Smuzhiyun 	int idx, s_idx;
1308*4882a593Smuzhiyun 	int h, s_h;
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun 	if (cb->strict_check) {
1311*4882a593Smuzhiyun 		struct netlink_ext_ack *extack = cb->extack;
1312*4882a593Smuzhiyun 		struct netconfmsg *ncm;
1313*4882a593Smuzhiyun 
1314*4882a593Smuzhiyun 		if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*ncm))) {
1315*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Invalid header for netconf dump request");
1316*4882a593Smuzhiyun 			return -EINVAL;
1317*4882a593Smuzhiyun 		}
1318*4882a593Smuzhiyun 
1319*4882a593Smuzhiyun 		if (nlmsg_attrlen(nlh, sizeof(*ncm))) {
1320*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Invalid data after header in netconf dump request");
1321*4882a593Smuzhiyun 			return -EINVAL;
1322*4882a593Smuzhiyun 		}
1323*4882a593Smuzhiyun 	}
1324*4882a593Smuzhiyun 
1325*4882a593Smuzhiyun 	s_h = cb->args[0];
1326*4882a593Smuzhiyun 	s_idx = idx = cb->args[1];
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun 	for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
1329*4882a593Smuzhiyun 		idx = 0;
1330*4882a593Smuzhiyun 		head = &net->dev_index_head[h];
1331*4882a593Smuzhiyun 		rcu_read_lock();
1332*4882a593Smuzhiyun 		cb->seq = net->dev_base_seq;
1333*4882a593Smuzhiyun 		hlist_for_each_entry_rcu(dev, head, index_hlist) {
1334*4882a593Smuzhiyun 			if (idx < s_idx)
1335*4882a593Smuzhiyun 				goto cont;
1336*4882a593Smuzhiyun 			mdev = mpls_dev_get(dev);
1337*4882a593Smuzhiyun 			if (!mdev)
1338*4882a593Smuzhiyun 				goto cont;
1339*4882a593Smuzhiyun 			if (mpls_netconf_fill_devconf(skb, mdev,
1340*4882a593Smuzhiyun 						      NETLINK_CB(cb->skb).portid,
1341*4882a593Smuzhiyun 						      nlh->nlmsg_seq,
1342*4882a593Smuzhiyun 						      RTM_NEWNETCONF,
1343*4882a593Smuzhiyun 						      NLM_F_MULTI,
1344*4882a593Smuzhiyun 						      NETCONFA_ALL) < 0) {
1345*4882a593Smuzhiyun 				rcu_read_unlock();
1346*4882a593Smuzhiyun 				goto done;
1347*4882a593Smuzhiyun 			}
1348*4882a593Smuzhiyun 			nl_dump_check_consistent(cb, nlmsg_hdr(skb));
1349*4882a593Smuzhiyun cont:
1350*4882a593Smuzhiyun 			idx++;
1351*4882a593Smuzhiyun 		}
1352*4882a593Smuzhiyun 		rcu_read_unlock();
1353*4882a593Smuzhiyun 	}
1354*4882a593Smuzhiyun done:
1355*4882a593Smuzhiyun 	cb->args[0] = h;
1356*4882a593Smuzhiyun 	cb->args[1] = idx;
1357*4882a593Smuzhiyun 
1358*4882a593Smuzhiyun 	return skb->len;
1359*4882a593Smuzhiyun }
1360*4882a593Smuzhiyun 
1361*4882a593Smuzhiyun #define MPLS_PERDEV_SYSCTL_OFFSET(field)	\
1362*4882a593Smuzhiyun 	(&((struct mpls_dev *)0)->field)
1363*4882a593Smuzhiyun 
mpls_conf_proc(struct ctl_table * ctl,int write,void * buffer,size_t * lenp,loff_t * ppos)1364*4882a593Smuzhiyun static int mpls_conf_proc(struct ctl_table *ctl, int write,
1365*4882a593Smuzhiyun 			  void *buffer, size_t *lenp, loff_t *ppos)
1366*4882a593Smuzhiyun {
1367*4882a593Smuzhiyun 	int oval = *(int *)ctl->data;
1368*4882a593Smuzhiyun 	int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
1369*4882a593Smuzhiyun 
1370*4882a593Smuzhiyun 	if (write) {
1371*4882a593Smuzhiyun 		struct mpls_dev *mdev = ctl->extra1;
1372*4882a593Smuzhiyun 		int i = (int *)ctl->data - (int *)mdev;
1373*4882a593Smuzhiyun 		struct net *net = ctl->extra2;
1374*4882a593Smuzhiyun 		int val = *(int *)ctl->data;
1375*4882a593Smuzhiyun 
1376*4882a593Smuzhiyun 		if (i == offsetof(struct mpls_dev, input_enabled) &&
1377*4882a593Smuzhiyun 		    val != oval) {
1378*4882a593Smuzhiyun 			mpls_netconf_notify_devconf(net, RTM_NEWNETCONF,
1379*4882a593Smuzhiyun 						    NETCONFA_INPUT, mdev);
1380*4882a593Smuzhiyun 		}
1381*4882a593Smuzhiyun 	}
1382*4882a593Smuzhiyun 
1383*4882a593Smuzhiyun 	return ret;
1384*4882a593Smuzhiyun }
1385*4882a593Smuzhiyun 
1386*4882a593Smuzhiyun static const struct ctl_table mpls_dev_table[] = {
1387*4882a593Smuzhiyun 	{
1388*4882a593Smuzhiyun 		.procname	= "input",
1389*4882a593Smuzhiyun 		.maxlen		= sizeof(int),
1390*4882a593Smuzhiyun 		.mode		= 0644,
1391*4882a593Smuzhiyun 		.proc_handler	= mpls_conf_proc,
1392*4882a593Smuzhiyun 		.data		= MPLS_PERDEV_SYSCTL_OFFSET(input_enabled),
1393*4882a593Smuzhiyun 	},
1394*4882a593Smuzhiyun 	{ }
1395*4882a593Smuzhiyun };
1396*4882a593Smuzhiyun 
mpls_dev_sysctl_register(struct net_device * dev,struct mpls_dev * mdev)1397*4882a593Smuzhiyun static int mpls_dev_sysctl_register(struct net_device *dev,
1398*4882a593Smuzhiyun 				    struct mpls_dev *mdev)
1399*4882a593Smuzhiyun {
1400*4882a593Smuzhiyun 	char path[sizeof("net/mpls/conf/") + IFNAMSIZ];
1401*4882a593Smuzhiyun 	struct net *net = dev_net(dev);
1402*4882a593Smuzhiyun 	struct ctl_table *table;
1403*4882a593Smuzhiyun 	int i;
1404*4882a593Smuzhiyun 
1405*4882a593Smuzhiyun 	table = kmemdup(&mpls_dev_table, sizeof(mpls_dev_table), GFP_KERNEL);
1406*4882a593Smuzhiyun 	if (!table)
1407*4882a593Smuzhiyun 		goto out;
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun 	/* Table data contains only offsets relative to the base of
1410*4882a593Smuzhiyun 	 * the mdev at this point, so make them absolute.
1411*4882a593Smuzhiyun 	 */
1412*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(mpls_dev_table); i++) {
1413*4882a593Smuzhiyun 		table[i].data = (char *)mdev + (uintptr_t)table[i].data;
1414*4882a593Smuzhiyun 		table[i].extra1 = mdev;
1415*4882a593Smuzhiyun 		table[i].extra2 = net;
1416*4882a593Smuzhiyun 	}
1417*4882a593Smuzhiyun 
1418*4882a593Smuzhiyun 	snprintf(path, sizeof(path), "net/mpls/conf/%s", dev->name);
1419*4882a593Smuzhiyun 
1420*4882a593Smuzhiyun 	mdev->sysctl = register_net_sysctl(net, path, table);
1421*4882a593Smuzhiyun 	if (!mdev->sysctl)
1422*4882a593Smuzhiyun 		goto free;
1423*4882a593Smuzhiyun 
1424*4882a593Smuzhiyun 	mpls_netconf_notify_devconf(net, RTM_NEWNETCONF, NETCONFA_ALL, mdev);
1425*4882a593Smuzhiyun 	return 0;
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun free:
1428*4882a593Smuzhiyun 	kfree(table);
1429*4882a593Smuzhiyun out:
1430*4882a593Smuzhiyun 	return -ENOBUFS;
1431*4882a593Smuzhiyun }
1432*4882a593Smuzhiyun 
mpls_dev_sysctl_unregister(struct net_device * dev,struct mpls_dev * mdev)1433*4882a593Smuzhiyun static void mpls_dev_sysctl_unregister(struct net_device *dev,
1434*4882a593Smuzhiyun 				       struct mpls_dev *mdev)
1435*4882a593Smuzhiyun {
1436*4882a593Smuzhiyun 	struct net *net = dev_net(dev);
1437*4882a593Smuzhiyun 	struct ctl_table *table;
1438*4882a593Smuzhiyun 
1439*4882a593Smuzhiyun 	table = mdev->sysctl->ctl_table_arg;
1440*4882a593Smuzhiyun 	unregister_net_sysctl_table(mdev->sysctl);
1441*4882a593Smuzhiyun 	kfree(table);
1442*4882a593Smuzhiyun 
1443*4882a593Smuzhiyun 	mpls_netconf_notify_devconf(net, RTM_DELNETCONF, 0, mdev);
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun 
mpls_add_dev(struct net_device * dev)1446*4882a593Smuzhiyun static struct mpls_dev *mpls_add_dev(struct net_device *dev)
1447*4882a593Smuzhiyun {
1448*4882a593Smuzhiyun 	struct mpls_dev *mdev;
1449*4882a593Smuzhiyun 	int err = -ENOMEM;
1450*4882a593Smuzhiyun 	int i;
1451*4882a593Smuzhiyun 
1452*4882a593Smuzhiyun 	ASSERT_RTNL();
1453*4882a593Smuzhiyun 
1454*4882a593Smuzhiyun 	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
1455*4882a593Smuzhiyun 	if (!mdev)
1456*4882a593Smuzhiyun 		return ERR_PTR(err);
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 	mdev->stats = alloc_percpu(struct mpls_pcpu_stats);
1459*4882a593Smuzhiyun 	if (!mdev->stats)
1460*4882a593Smuzhiyun 		goto free;
1461*4882a593Smuzhiyun 
1462*4882a593Smuzhiyun 	for_each_possible_cpu(i) {
1463*4882a593Smuzhiyun 		struct mpls_pcpu_stats *mpls_stats;
1464*4882a593Smuzhiyun 
1465*4882a593Smuzhiyun 		mpls_stats = per_cpu_ptr(mdev->stats, i);
1466*4882a593Smuzhiyun 		u64_stats_init(&mpls_stats->syncp);
1467*4882a593Smuzhiyun 	}
1468*4882a593Smuzhiyun 
1469*4882a593Smuzhiyun 	mdev->dev = dev;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	err = mpls_dev_sysctl_register(dev, mdev);
1472*4882a593Smuzhiyun 	if (err)
1473*4882a593Smuzhiyun 		goto free;
1474*4882a593Smuzhiyun 
1475*4882a593Smuzhiyun 	rcu_assign_pointer(dev->mpls_ptr, mdev);
1476*4882a593Smuzhiyun 
1477*4882a593Smuzhiyun 	return mdev;
1478*4882a593Smuzhiyun 
1479*4882a593Smuzhiyun free:
1480*4882a593Smuzhiyun 	free_percpu(mdev->stats);
1481*4882a593Smuzhiyun 	kfree(mdev);
1482*4882a593Smuzhiyun 	return ERR_PTR(err);
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun 
mpls_dev_destroy_rcu(struct rcu_head * head)1485*4882a593Smuzhiyun static void mpls_dev_destroy_rcu(struct rcu_head *head)
1486*4882a593Smuzhiyun {
1487*4882a593Smuzhiyun 	struct mpls_dev *mdev = container_of(head, struct mpls_dev, rcu);
1488*4882a593Smuzhiyun 
1489*4882a593Smuzhiyun 	free_percpu(mdev->stats);
1490*4882a593Smuzhiyun 	kfree(mdev);
1491*4882a593Smuzhiyun }
1492*4882a593Smuzhiyun 
mpls_ifdown(struct net_device * dev,int event)1493*4882a593Smuzhiyun static int mpls_ifdown(struct net_device *dev, int event)
1494*4882a593Smuzhiyun {
1495*4882a593Smuzhiyun 	struct mpls_route __rcu **platform_label;
1496*4882a593Smuzhiyun 	struct net *net = dev_net(dev);
1497*4882a593Smuzhiyun 	unsigned index;
1498*4882a593Smuzhiyun 
1499*4882a593Smuzhiyun 	platform_label = rtnl_dereference(net->mpls.platform_label);
1500*4882a593Smuzhiyun 	for (index = 0; index < net->mpls.platform_labels; index++) {
1501*4882a593Smuzhiyun 		struct mpls_route *rt = rtnl_dereference(platform_label[index]);
1502*4882a593Smuzhiyun 		bool nh_del = false;
1503*4882a593Smuzhiyun 		u8 alive = 0;
1504*4882a593Smuzhiyun 
1505*4882a593Smuzhiyun 		if (!rt)
1506*4882a593Smuzhiyun 			continue;
1507*4882a593Smuzhiyun 
1508*4882a593Smuzhiyun 		if (event == NETDEV_UNREGISTER) {
1509*4882a593Smuzhiyun 			u8 deleted = 0;
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 			for_nexthops(rt) {
1512*4882a593Smuzhiyun 				struct net_device *nh_dev =
1513*4882a593Smuzhiyun 					rtnl_dereference(nh->nh_dev);
1514*4882a593Smuzhiyun 
1515*4882a593Smuzhiyun 				if (!nh_dev || nh_dev == dev)
1516*4882a593Smuzhiyun 					deleted++;
1517*4882a593Smuzhiyun 				if (nh_dev == dev)
1518*4882a593Smuzhiyun 					nh_del = true;
1519*4882a593Smuzhiyun 			} endfor_nexthops(rt);
1520*4882a593Smuzhiyun 
1521*4882a593Smuzhiyun 			/* if there are no more nexthops, delete the route */
1522*4882a593Smuzhiyun 			if (deleted == rt->rt_nhn) {
1523*4882a593Smuzhiyun 				mpls_route_update(net, index, NULL, NULL);
1524*4882a593Smuzhiyun 				continue;
1525*4882a593Smuzhiyun 			}
1526*4882a593Smuzhiyun 
1527*4882a593Smuzhiyun 			if (nh_del) {
1528*4882a593Smuzhiyun 				size_t size = sizeof(*rt) + rt->rt_nhn *
1529*4882a593Smuzhiyun 					rt->rt_nh_size;
1530*4882a593Smuzhiyun 				struct mpls_route *orig = rt;
1531*4882a593Smuzhiyun 
1532*4882a593Smuzhiyun 				rt = kmalloc(size, GFP_KERNEL);
1533*4882a593Smuzhiyun 				if (!rt)
1534*4882a593Smuzhiyun 					return -ENOMEM;
1535*4882a593Smuzhiyun 				memcpy(rt, orig, size);
1536*4882a593Smuzhiyun 			}
1537*4882a593Smuzhiyun 		}
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun 		change_nexthops(rt) {
1540*4882a593Smuzhiyun 			unsigned int nh_flags = nh->nh_flags;
1541*4882a593Smuzhiyun 
1542*4882a593Smuzhiyun 			if (rtnl_dereference(nh->nh_dev) != dev)
1543*4882a593Smuzhiyun 				goto next;
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun 			switch (event) {
1546*4882a593Smuzhiyun 			case NETDEV_DOWN:
1547*4882a593Smuzhiyun 			case NETDEV_UNREGISTER:
1548*4882a593Smuzhiyun 				nh_flags |= RTNH_F_DEAD;
1549*4882a593Smuzhiyun 				fallthrough;
1550*4882a593Smuzhiyun 			case NETDEV_CHANGE:
1551*4882a593Smuzhiyun 				nh_flags |= RTNH_F_LINKDOWN;
1552*4882a593Smuzhiyun 				break;
1553*4882a593Smuzhiyun 			}
1554*4882a593Smuzhiyun 			if (event == NETDEV_UNREGISTER)
1555*4882a593Smuzhiyun 				RCU_INIT_POINTER(nh->nh_dev, NULL);
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun 			if (nh->nh_flags != nh_flags)
1558*4882a593Smuzhiyun 				WRITE_ONCE(nh->nh_flags, nh_flags);
1559*4882a593Smuzhiyun next:
1560*4882a593Smuzhiyun 			if (!(nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)))
1561*4882a593Smuzhiyun 				alive++;
1562*4882a593Smuzhiyun 		} endfor_nexthops(rt);
1563*4882a593Smuzhiyun 
1564*4882a593Smuzhiyun 		WRITE_ONCE(rt->rt_nhn_alive, alive);
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun 		if (nh_del)
1567*4882a593Smuzhiyun 			mpls_route_update(net, index, rt, NULL);
1568*4882a593Smuzhiyun 	}
1569*4882a593Smuzhiyun 
1570*4882a593Smuzhiyun 	return 0;
1571*4882a593Smuzhiyun }
1572*4882a593Smuzhiyun 
mpls_ifup(struct net_device * dev,unsigned int flags)1573*4882a593Smuzhiyun static void mpls_ifup(struct net_device *dev, unsigned int flags)
1574*4882a593Smuzhiyun {
1575*4882a593Smuzhiyun 	struct mpls_route __rcu **platform_label;
1576*4882a593Smuzhiyun 	struct net *net = dev_net(dev);
1577*4882a593Smuzhiyun 	unsigned index;
1578*4882a593Smuzhiyun 	u8 alive;
1579*4882a593Smuzhiyun 
1580*4882a593Smuzhiyun 	platform_label = rtnl_dereference(net->mpls.platform_label);
1581*4882a593Smuzhiyun 	for (index = 0; index < net->mpls.platform_labels; index++) {
1582*4882a593Smuzhiyun 		struct mpls_route *rt = rtnl_dereference(platform_label[index]);
1583*4882a593Smuzhiyun 
1584*4882a593Smuzhiyun 		if (!rt)
1585*4882a593Smuzhiyun 			continue;
1586*4882a593Smuzhiyun 
1587*4882a593Smuzhiyun 		alive = 0;
1588*4882a593Smuzhiyun 		change_nexthops(rt) {
1589*4882a593Smuzhiyun 			unsigned int nh_flags = nh->nh_flags;
1590*4882a593Smuzhiyun 			struct net_device *nh_dev =
1591*4882a593Smuzhiyun 				rtnl_dereference(nh->nh_dev);
1592*4882a593Smuzhiyun 
1593*4882a593Smuzhiyun 			if (!(nh_flags & flags)) {
1594*4882a593Smuzhiyun 				alive++;
1595*4882a593Smuzhiyun 				continue;
1596*4882a593Smuzhiyun 			}
1597*4882a593Smuzhiyun 			if (nh_dev != dev)
1598*4882a593Smuzhiyun 				continue;
1599*4882a593Smuzhiyun 			alive++;
1600*4882a593Smuzhiyun 			nh_flags &= ~flags;
1601*4882a593Smuzhiyun 			WRITE_ONCE(nh->nh_flags, nh_flags);
1602*4882a593Smuzhiyun 		} endfor_nexthops(rt);
1603*4882a593Smuzhiyun 
1604*4882a593Smuzhiyun 		WRITE_ONCE(rt->rt_nhn_alive, alive);
1605*4882a593Smuzhiyun 	}
1606*4882a593Smuzhiyun }
1607*4882a593Smuzhiyun 
mpls_dev_notify(struct notifier_block * this,unsigned long event,void * ptr)1608*4882a593Smuzhiyun static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
1609*4882a593Smuzhiyun 			   void *ptr)
1610*4882a593Smuzhiyun {
1611*4882a593Smuzhiyun 	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
1612*4882a593Smuzhiyun 	struct mpls_dev *mdev;
1613*4882a593Smuzhiyun 	unsigned int flags;
1614*4882a593Smuzhiyun 
1615*4882a593Smuzhiyun 	if (event == NETDEV_REGISTER) {
1616*4882a593Smuzhiyun 		mdev = mpls_add_dev(dev);
1617*4882a593Smuzhiyun 		if (IS_ERR(mdev))
1618*4882a593Smuzhiyun 			return notifier_from_errno(PTR_ERR(mdev));
1619*4882a593Smuzhiyun 
1620*4882a593Smuzhiyun 		return NOTIFY_OK;
1621*4882a593Smuzhiyun 	}
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun 	mdev = mpls_dev_get(dev);
1624*4882a593Smuzhiyun 	if (!mdev)
1625*4882a593Smuzhiyun 		return NOTIFY_OK;
1626*4882a593Smuzhiyun 
1627*4882a593Smuzhiyun 	switch (event) {
1628*4882a593Smuzhiyun 		int err;
1629*4882a593Smuzhiyun 
1630*4882a593Smuzhiyun 	case NETDEV_DOWN:
1631*4882a593Smuzhiyun 		err = mpls_ifdown(dev, event);
1632*4882a593Smuzhiyun 		if (err)
1633*4882a593Smuzhiyun 			return notifier_from_errno(err);
1634*4882a593Smuzhiyun 		break;
1635*4882a593Smuzhiyun 	case NETDEV_UP:
1636*4882a593Smuzhiyun 		flags = dev_get_flags(dev);
1637*4882a593Smuzhiyun 		if (flags & (IFF_RUNNING | IFF_LOWER_UP))
1638*4882a593Smuzhiyun 			mpls_ifup(dev, RTNH_F_DEAD | RTNH_F_LINKDOWN);
1639*4882a593Smuzhiyun 		else
1640*4882a593Smuzhiyun 			mpls_ifup(dev, RTNH_F_DEAD);
1641*4882a593Smuzhiyun 		break;
1642*4882a593Smuzhiyun 	case NETDEV_CHANGE:
1643*4882a593Smuzhiyun 		flags = dev_get_flags(dev);
1644*4882a593Smuzhiyun 		if (flags & (IFF_RUNNING | IFF_LOWER_UP)) {
1645*4882a593Smuzhiyun 			mpls_ifup(dev, RTNH_F_DEAD | RTNH_F_LINKDOWN);
1646*4882a593Smuzhiyun 		} else {
1647*4882a593Smuzhiyun 			err = mpls_ifdown(dev, event);
1648*4882a593Smuzhiyun 			if (err)
1649*4882a593Smuzhiyun 				return notifier_from_errno(err);
1650*4882a593Smuzhiyun 		}
1651*4882a593Smuzhiyun 		break;
1652*4882a593Smuzhiyun 	case NETDEV_UNREGISTER:
1653*4882a593Smuzhiyun 		err = mpls_ifdown(dev, event);
1654*4882a593Smuzhiyun 		if (err)
1655*4882a593Smuzhiyun 			return notifier_from_errno(err);
1656*4882a593Smuzhiyun 		mdev = mpls_dev_get(dev);
1657*4882a593Smuzhiyun 		if (mdev) {
1658*4882a593Smuzhiyun 			mpls_dev_sysctl_unregister(dev, mdev);
1659*4882a593Smuzhiyun 			RCU_INIT_POINTER(dev->mpls_ptr, NULL);
1660*4882a593Smuzhiyun 			call_rcu(&mdev->rcu, mpls_dev_destroy_rcu);
1661*4882a593Smuzhiyun 		}
1662*4882a593Smuzhiyun 		break;
1663*4882a593Smuzhiyun 	case NETDEV_CHANGENAME:
1664*4882a593Smuzhiyun 		mdev = mpls_dev_get(dev);
1665*4882a593Smuzhiyun 		if (mdev) {
1666*4882a593Smuzhiyun 			mpls_dev_sysctl_unregister(dev, mdev);
1667*4882a593Smuzhiyun 			err = mpls_dev_sysctl_register(dev, mdev);
1668*4882a593Smuzhiyun 			if (err)
1669*4882a593Smuzhiyun 				return notifier_from_errno(err);
1670*4882a593Smuzhiyun 		}
1671*4882a593Smuzhiyun 		break;
1672*4882a593Smuzhiyun 	}
1673*4882a593Smuzhiyun 	return NOTIFY_OK;
1674*4882a593Smuzhiyun }
1675*4882a593Smuzhiyun 
1676*4882a593Smuzhiyun static struct notifier_block mpls_dev_notifier = {
1677*4882a593Smuzhiyun 	.notifier_call = mpls_dev_notify,
1678*4882a593Smuzhiyun };
1679*4882a593Smuzhiyun 
nla_put_via(struct sk_buff * skb,u8 table,const void * addr,int alen)1680*4882a593Smuzhiyun static int nla_put_via(struct sk_buff *skb,
1681*4882a593Smuzhiyun 		       u8 table, const void *addr, int alen)
1682*4882a593Smuzhiyun {
1683*4882a593Smuzhiyun 	static const int table_to_family[NEIGH_NR_TABLES + 1] = {
1684*4882a593Smuzhiyun 		AF_INET, AF_INET6, AF_DECnet, AF_PACKET,
1685*4882a593Smuzhiyun 	};
1686*4882a593Smuzhiyun 	struct nlattr *nla;
1687*4882a593Smuzhiyun 	struct rtvia *via;
1688*4882a593Smuzhiyun 	int family = AF_UNSPEC;
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun 	nla = nla_reserve(skb, RTA_VIA, alen + 2);
1691*4882a593Smuzhiyun 	if (!nla)
1692*4882a593Smuzhiyun 		return -EMSGSIZE;
1693*4882a593Smuzhiyun 
1694*4882a593Smuzhiyun 	if (table <= NEIGH_NR_TABLES)
1695*4882a593Smuzhiyun 		family = table_to_family[table];
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun 	via = nla_data(nla);
1698*4882a593Smuzhiyun 	via->rtvia_family = family;
1699*4882a593Smuzhiyun 	memcpy(via->rtvia_addr, addr, alen);
1700*4882a593Smuzhiyun 	return 0;
1701*4882a593Smuzhiyun }
1702*4882a593Smuzhiyun 
nla_put_labels(struct sk_buff * skb,int attrtype,u8 labels,const u32 label[])1703*4882a593Smuzhiyun int nla_put_labels(struct sk_buff *skb, int attrtype,
1704*4882a593Smuzhiyun 		   u8 labels, const u32 label[])
1705*4882a593Smuzhiyun {
1706*4882a593Smuzhiyun 	struct nlattr *nla;
1707*4882a593Smuzhiyun 	struct mpls_shim_hdr *nla_label;
1708*4882a593Smuzhiyun 	bool bos;
1709*4882a593Smuzhiyun 	int i;
1710*4882a593Smuzhiyun 	nla = nla_reserve(skb, attrtype, labels*4);
1711*4882a593Smuzhiyun 	if (!nla)
1712*4882a593Smuzhiyun 		return -EMSGSIZE;
1713*4882a593Smuzhiyun 
1714*4882a593Smuzhiyun 	nla_label = nla_data(nla);
1715*4882a593Smuzhiyun 	bos = true;
1716*4882a593Smuzhiyun 	for (i = labels - 1; i >= 0; i--) {
1717*4882a593Smuzhiyun 		nla_label[i] = mpls_entry_encode(label[i], 0, 0, bos);
1718*4882a593Smuzhiyun 		bos = false;
1719*4882a593Smuzhiyun 	}
1720*4882a593Smuzhiyun 
1721*4882a593Smuzhiyun 	return 0;
1722*4882a593Smuzhiyun }
1723*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(nla_put_labels);
1724*4882a593Smuzhiyun 
nla_get_labels(const struct nlattr * nla,u8 max_labels,u8 * labels,u32 label[],struct netlink_ext_ack * extack)1725*4882a593Smuzhiyun int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
1726*4882a593Smuzhiyun 		   u32 label[], struct netlink_ext_ack *extack)
1727*4882a593Smuzhiyun {
1728*4882a593Smuzhiyun 	unsigned len = nla_len(nla);
1729*4882a593Smuzhiyun 	struct mpls_shim_hdr *nla_label;
1730*4882a593Smuzhiyun 	u8 nla_labels;
1731*4882a593Smuzhiyun 	bool bos;
1732*4882a593Smuzhiyun 	int i;
1733*4882a593Smuzhiyun 
1734*4882a593Smuzhiyun 	/* len needs to be an even multiple of 4 (the label size). Number
1735*4882a593Smuzhiyun 	 * of labels is a u8 so check for overflow.
1736*4882a593Smuzhiyun 	 */
1737*4882a593Smuzhiyun 	if (len & 3 || len / 4 > 255) {
1738*4882a593Smuzhiyun 		NL_SET_ERR_MSG_ATTR(extack, nla,
1739*4882a593Smuzhiyun 				    "Invalid length for labels attribute");
1740*4882a593Smuzhiyun 		return -EINVAL;
1741*4882a593Smuzhiyun 	}
1742*4882a593Smuzhiyun 
1743*4882a593Smuzhiyun 	/* Limit the number of new labels allowed */
1744*4882a593Smuzhiyun 	nla_labels = len/4;
1745*4882a593Smuzhiyun 	if (nla_labels > max_labels) {
1746*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Too many labels");
1747*4882a593Smuzhiyun 		return -EINVAL;
1748*4882a593Smuzhiyun 	}
1749*4882a593Smuzhiyun 
1750*4882a593Smuzhiyun 	/* when label == NULL, caller wants number of labels */
1751*4882a593Smuzhiyun 	if (!label)
1752*4882a593Smuzhiyun 		goto out;
1753*4882a593Smuzhiyun 
1754*4882a593Smuzhiyun 	nla_label = nla_data(nla);
1755*4882a593Smuzhiyun 	bos = true;
1756*4882a593Smuzhiyun 	for (i = nla_labels - 1; i >= 0; i--, bos = false) {
1757*4882a593Smuzhiyun 		struct mpls_entry_decoded dec;
1758*4882a593Smuzhiyun 		dec = mpls_entry_decode(nla_label + i);
1759*4882a593Smuzhiyun 
1760*4882a593Smuzhiyun 		/* Ensure the bottom of stack flag is properly set
1761*4882a593Smuzhiyun 		 * and ttl and tc are both clear.
1762*4882a593Smuzhiyun 		 */
1763*4882a593Smuzhiyun 		if (dec.ttl) {
1764*4882a593Smuzhiyun 			NL_SET_ERR_MSG_ATTR(extack, nla,
1765*4882a593Smuzhiyun 					    "TTL in label must be 0");
1766*4882a593Smuzhiyun 			return -EINVAL;
1767*4882a593Smuzhiyun 		}
1768*4882a593Smuzhiyun 
1769*4882a593Smuzhiyun 		if (dec.tc) {
1770*4882a593Smuzhiyun 			NL_SET_ERR_MSG_ATTR(extack, nla,
1771*4882a593Smuzhiyun 					    "Traffic class in label must be 0");
1772*4882a593Smuzhiyun 			return -EINVAL;
1773*4882a593Smuzhiyun 		}
1774*4882a593Smuzhiyun 
1775*4882a593Smuzhiyun 		if (dec.bos != bos) {
1776*4882a593Smuzhiyun 			NL_SET_BAD_ATTR(extack, nla);
1777*4882a593Smuzhiyun 			if (bos) {
1778*4882a593Smuzhiyun 				NL_SET_ERR_MSG(extack,
1779*4882a593Smuzhiyun 					       "BOS bit must be set in first label");
1780*4882a593Smuzhiyun 			} else {
1781*4882a593Smuzhiyun 				NL_SET_ERR_MSG(extack,
1782*4882a593Smuzhiyun 					       "BOS bit can only be set in first label");
1783*4882a593Smuzhiyun 			}
1784*4882a593Smuzhiyun 			return -EINVAL;
1785*4882a593Smuzhiyun 		}
1786*4882a593Smuzhiyun 
1787*4882a593Smuzhiyun 		switch (dec.label) {
1788*4882a593Smuzhiyun 		case MPLS_LABEL_IMPLNULL:
1789*4882a593Smuzhiyun 			/* RFC3032: This is a label that an LSR may
1790*4882a593Smuzhiyun 			 * assign and distribute, but which never
1791*4882a593Smuzhiyun 			 * actually appears in the encapsulation.
1792*4882a593Smuzhiyun 			 */
1793*4882a593Smuzhiyun 			NL_SET_ERR_MSG_ATTR(extack, nla,
1794*4882a593Smuzhiyun 					    "Implicit NULL Label (3) can not be used in encapsulation");
1795*4882a593Smuzhiyun 			return -EINVAL;
1796*4882a593Smuzhiyun 		}
1797*4882a593Smuzhiyun 
1798*4882a593Smuzhiyun 		label[i] = dec.label;
1799*4882a593Smuzhiyun 	}
1800*4882a593Smuzhiyun out:
1801*4882a593Smuzhiyun 	*labels = nla_labels;
1802*4882a593Smuzhiyun 	return 0;
1803*4882a593Smuzhiyun }
1804*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(nla_get_labels);
1805*4882a593Smuzhiyun 
rtm_to_route_config(struct sk_buff * skb,struct nlmsghdr * nlh,struct mpls_route_config * cfg,struct netlink_ext_ack * extack)1806*4882a593Smuzhiyun static int rtm_to_route_config(struct sk_buff *skb,
1807*4882a593Smuzhiyun 			       struct nlmsghdr *nlh,
1808*4882a593Smuzhiyun 			       struct mpls_route_config *cfg,
1809*4882a593Smuzhiyun 			       struct netlink_ext_ack *extack)
1810*4882a593Smuzhiyun {
1811*4882a593Smuzhiyun 	struct rtmsg *rtm;
1812*4882a593Smuzhiyun 	struct nlattr *tb[RTA_MAX+1];
1813*4882a593Smuzhiyun 	int index;
1814*4882a593Smuzhiyun 	int err;
1815*4882a593Smuzhiyun 
1816*4882a593Smuzhiyun 	err = nlmsg_parse_deprecated(nlh, sizeof(*rtm), tb, RTA_MAX,
1817*4882a593Smuzhiyun 				     rtm_mpls_policy, extack);
1818*4882a593Smuzhiyun 	if (err < 0)
1819*4882a593Smuzhiyun 		goto errout;
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun 	err = -EINVAL;
1822*4882a593Smuzhiyun 	rtm = nlmsg_data(nlh);
1823*4882a593Smuzhiyun 
1824*4882a593Smuzhiyun 	if (rtm->rtm_family != AF_MPLS) {
1825*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "Invalid address family in rtmsg");
1826*4882a593Smuzhiyun 		goto errout;
1827*4882a593Smuzhiyun 	}
1828*4882a593Smuzhiyun 	if (rtm->rtm_dst_len != 20) {
1829*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "rtm_dst_len must be 20 for MPLS");
1830*4882a593Smuzhiyun 		goto errout;
1831*4882a593Smuzhiyun 	}
1832*4882a593Smuzhiyun 	if (rtm->rtm_src_len != 0) {
1833*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "rtm_src_len must be 0 for MPLS");
1834*4882a593Smuzhiyun 		goto errout;
1835*4882a593Smuzhiyun 	}
1836*4882a593Smuzhiyun 	if (rtm->rtm_tos != 0) {
1837*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "rtm_tos must be 0 for MPLS");
1838*4882a593Smuzhiyun 		goto errout;
1839*4882a593Smuzhiyun 	}
1840*4882a593Smuzhiyun 	if (rtm->rtm_table != RT_TABLE_MAIN) {
1841*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack,
1842*4882a593Smuzhiyun 			       "MPLS only supports the main route table");
1843*4882a593Smuzhiyun 		goto errout;
1844*4882a593Smuzhiyun 	}
1845*4882a593Smuzhiyun 	/* Any value is acceptable for rtm_protocol */
1846*4882a593Smuzhiyun 
1847*4882a593Smuzhiyun 	/* As mpls uses destination specific addresses
1848*4882a593Smuzhiyun 	 * (or source specific address in the case of multicast)
1849*4882a593Smuzhiyun 	 * all addresses have universal scope.
1850*4882a593Smuzhiyun 	 */
1851*4882a593Smuzhiyun 	if (rtm->rtm_scope != RT_SCOPE_UNIVERSE) {
1852*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack,
1853*4882a593Smuzhiyun 			       "Invalid route scope  - MPLS only supports UNIVERSE");
1854*4882a593Smuzhiyun 		goto errout;
1855*4882a593Smuzhiyun 	}
1856*4882a593Smuzhiyun 	if (rtm->rtm_type != RTN_UNICAST) {
1857*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack,
1858*4882a593Smuzhiyun 			       "Invalid route type - MPLS only supports UNICAST");
1859*4882a593Smuzhiyun 		goto errout;
1860*4882a593Smuzhiyun 	}
1861*4882a593Smuzhiyun 	if (rtm->rtm_flags != 0) {
1862*4882a593Smuzhiyun 		NL_SET_ERR_MSG(extack, "rtm_flags must be 0 for MPLS");
1863*4882a593Smuzhiyun 		goto errout;
1864*4882a593Smuzhiyun 	}
1865*4882a593Smuzhiyun 
1866*4882a593Smuzhiyun 	cfg->rc_label		= LABEL_NOT_SPECIFIED;
1867*4882a593Smuzhiyun 	cfg->rc_protocol	= rtm->rtm_protocol;
1868*4882a593Smuzhiyun 	cfg->rc_via_table	= MPLS_NEIGH_TABLE_UNSPEC;
1869*4882a593Smuzhiyun 	cfg->rc_ttl_propagate	= MPLS_TTL_PROP_DEFAULT;
1870*4882a593Smuzhiyun 	cfg->rc_nlflags		= nlh->nlmsg_flags;
1871*4882a593Smuzhiyun 	cfg->rc_nlinfo.portid	= NETLINK_CB(skb).portid;
1872*4882a593Smuzhiyun 	cfg->rc_nlinfo.nlh	= nlh;
1873*4882a593Smuzhiyun 	cfg->rc_nlinfo.nl_net	= sock_net(skb->sk);
1874*4882a593Smuzhiyun 
1875*4882a593Smuzhiyun 	for (index = 0; index <= RTA_MAX; index++) {
1876*4882a593Smuzhiyun 		struct nlattr *nla = tb[index];
1877*4882a593Smuzhiyun 		if (!nla)
1878*4882a593Smuzhiyun 			continue;
1879*4882a593Smuzhiyun 
1880*4882a593Smuzhiyun 		switch (index) {
1881*4882a593Smuzhiyun 		case RTA_OIF:
1882*4882a593Smuzhiyun 			cfg->rc_ifindex = nla_get_u32(nla);
1883*4882a593Smuzhiyun 			break;
1884*4882a593Smuzhiyun 		case RTA_NEWDST:
1885*4882a593Smuzhiyun 			if (nla_get_labels(nla, MAX_NEW_LABELS,
1886*4882a593Smuzhiyun 					   &cfg->rc_output_labels,
1887*4882a593Smuzhiyun 					   cfg->rc_output_label, extack))
1888*4882a593Smuzhiyun 				goto errout;
1889*4882a593Smuzhiyun 			break;
1890*4882a593Smuzhiyun 		case RTA_DST:
1891*4882a593Smuzhiyun 		{
1892*4882a593Smuzhiyun 			u8 label_count;
1893*4882a593Smuzhiyun 			if (nla_get_labels(nla, 1, &label_count,
1894*4882a593Smuzhiyun 					   &cfg->rc_label, extack))
1895*4882a593Smuzhiyun 				goto errout;
1896*4882a593Smuzhiyun 
1897*4882a593Smuzhiyun 			if (!mpls_label_ok(cfg->rc_nlinfo.nl_net,
1898*4882a593Smuzhiyun 					   &cfg->rc_label, extack))
1899*4882a593Smuzhiyun 				goto errout;
1900*4882a593Smuzhiyun 			break;
1901*4882a593Smuzhiyun 		}
1902*4882a593Smuzhiyun 		case RTA_GATEWAY:
1903*4882a593Smuzhiyun 			NL_SET_ERR_MSG(extack, "MPLS does not support RTA_GATEWAY attribute");
1904*4882a593Smuzhiyun 			goto errout;
1905*4882a593Smuzhiyun 		case RTA_VIA:
1906*4882a593Smuzhiyun 		{
1907*4882a593Smuzhiyun 			if (nla_get_via(nla, &cfg->rc_via_alen,
1908*4882a593Smuzhiyun 					&cfg->rc_via_table, cfg->rc_via,
1909*4882a593Smuzhiyun 					extack))
1910*4882a593Smuzhiyun 				goto errout;
1911*4882a593Smuzhiyun 			break;
1912*4882a593Smuzhiyun 		}
1913*4882a593Smuzhiyun 		case RTA_MULTIPATH:
1914*4882a593Smuzhiyun 		{
1915*4882a593Smuzhiyun 			cfg->rc_mp = nla_data(nla);
1916*4882a593Smuzhiyun 			cfg->rc_mp_len = nla_len(nla);
1917*4882a593Smuzhiyun 			break;
1918*4882a593Smuzhiyun 		}
1919*4882a593Smuzhiyun 		case RTA_TTL_PROPAGATE:
1920*4882a593Smuzhiyun 		{
1921*4882a593Smuzhiyun 			u8 ttl_propagate = nla_get_u8(nla);
1922*4882a593Smuzhiyun 
1923*4882a593Smuzhiyun 			if (ttl_propagate > 1) {
1924*4882a593Smuzhiyun 				NL_SET_ERR_MSG_ATTR(extack, nla,
1925*4882a593Smuzhiyun 						    "RTA_TTL_PROPAGATE can only be 0 or 1");
1926*4882a593Smuzhiyun 				goto errout;
1927*4882a593Smuzhiyun 			}
1928*4882a593Smuzhiyun 			cfg->rc_ttl_propagate = ttl_propagate ?
1929*4882a593Smuzhiyun 				MPLS_TTL_PROP_ENABLED :
1930*4882a593Smuzhiyun 				MPLS_TTL_PROP_DISABLED;
1931*4882a593Smuzhiyun 			break;
1932*4882a593Smuzhiyun 		}
1933*4882a593Smuzhiyun 		default:
1934*4882a593Smuzhiyun 			NL_SET_ERR_MSG_ATTR(extack, nla, "Unknown attribute");
1935*4882a593Smuzhiyun 			/* Unsupported attribute */
1936*4882a593Smuzhiyun 			goto errout;
1937*4882a593Smuzhiyun 		}
1938*4882a593Smuzhiyun 	}
1939*4882a593Smuzhiyun 
1940*4882a593Smuzhiyun 	err = 0;
1941*4882a593Smuzhiyun errout:
1942*4882a593Smuzhiyun 	return err;
1943*4882a593Smuzhiyun }
1944*4882a593Smuzhiyun 
mpls_rtm_delroute(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)1945*4882a593Smuzhiyun static int mpls_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
1946*4882a593Smuzhiyun 			     struct netlink_ext_ack *extack)
1947*4882a593Smuzhiyun {
1948*4882a593Smuzhiyun 	struct mpls_route_config *cfg;
1949*4882a593Smuzhiyun 	int err;
1950*4882a593Smuzhiyun 
1951*4882a593Smuzhiyun 	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
1952*4882a593Smuzhiyun 	if (!cfg)
1953*4882a593Smuzhiyun 		return -ENOMEM;
1954*4882a593Smuzhiyun 
1955*4882a593Smuzhiyun 	err = rtm_to_route_config(skb, nlh, cfg, extack);
1956*4882a593Smuzhiyun 	if (err < 0)
1957*4882a593Smuzhiyun 		goto out;
1958*4882a593Smuzhiyun 
1959*4882a593Smuzhiyun 	err = mpls_route_del(cfg, extack);
1960*4882a593Smuzhiyun out:
1961*4882a593Smuzhiyun 	kfree(cfg);
1962*4882a593Smuzhiyun 
1963*4882a593Smuzhiyun 	return err;
1964*4882a593Smuzhiyun }
1965*4882a593Smuzhiyun 
1966*4882a593Smuzhiyun 
mpls_rtm_newroute(struct sk_buff * skb,struct nlmsghdr * nlh,struct netlink_ext_ack * extack)1967*4882a593Smuzhiyun static int mpls_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
1968*4882a593Smuzhiyun 			     struct netlink_ext_ack *extack)
1969*4882a593Smuzhiyun {
1970*4882a593Smuzhiyun 	struct mpls_route_config *cfg;
1971*4882a593Smuzhiyun 	int err;
1972*4882a593Smuzhiyun 
1973*4882a593Smuzhiyun 	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
1974*4882a593Smuzhiyun 	if (!cfg)
1975*4882a593Smuzhiyun 		return -ENOMEM;
1976*4882a593Smuzhiyun 
1977*4882a593Smuzhiyun 	err = rtm_to_route_config(skb, nlh, cfg, extack);
1978*4882a593Smuzhiyun 	if (err < 0)
1979*4882a593Smuzhiyun 		goto out;
1980*4882a593Smuzhiyun 
1981*4882a593Smuzhiyun 	err = mpls_route_add(cfg, extack);
1982*4882a593Smuzhiyun out:
1983*4882a593Smuzhiyun 	kfree(cfg);
1984*4882a593Smuzhiyun 
1985*4882a593Smuzhiyun 	return err;
1986*4882a593Smuzhiyun }
1987*4882a593Smuzhiyun 
mpls_dump_route(struct sk_buff * skb,u32 portid,u32 seq,int event,u32 label,struct mpls_route * rt,int flags)1988*4882a593Smuzhiyun static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
1989*4882a593Smuzhiyun 			   u32 label, struct mpls_route *rt, int flags)
1990*4882a593Smuzhiyun {
1991*4882a593Smuzhiyun 	struct net_device *dev;
1992*4882a593Smuzhiyun 	struct nlmsghdr *nlh;
1993*4882a593Smuzhiyun 	struct rtmsg *rtm;
1994*4882a593Smuzhiyun 
1995*4882a593Smuzhiyun 	nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags);
1996*4882a593Smuzhiyun 	if (nlh == NULL)
1997*4882a593Smuzhiyun 		return -EMSGSIZE;
1998*4882a593Smuzhiyun 
1999*4882a593Smuzhiyun 	rtm = nlmsg_data(nlh);
2000*4882a593Smuzhiyun 	rtm->rtm_family = AF_MPLS;
2001*4882a593Smuzhiyun 	rtm->rtm_dst_len = 20;
2002*4882a593Smuzhiyun 	rtm->rtm_src_len = 0;
2003*4882a593Smuzhiyun 	rtm->rtm_tos = 0;
2004*4882a593Smuzhiyun 	rtm->rtm_table = RT_TABLE_MAIN;
2005*4882a593Smuzhiyun 	rtm->rtm_protocol = rt->rt_protocol;
2006*4882a593Smuzhiyun 	rtm->rtm_scope = RT_SCOPE_UNIVERSE;
2007*4882a593Smuzhiyun 	rtm->rtm_type = RTN_UNICAST;
2008*4882a593Smuzhiyun 	rtm->rtm_flags = 0;
2009*4882a593Smuzhiyun 
2010*4882a593Smuzhiyun 	if (nla_put_labels(skb, RTA_DST, 1, &label))
2011*4882a593Smuzhiyun 		goto nla_put_failure;
2012*4882a593Smuzhiyun 
2013*4882a593Smuzhiyun 	if (rt->rt_ttl_propagate != MPLS_TTL_PROP_DEFAULT) {
2014*4882a593Smuzhiyun 		bool ttl_propagate =
2015*4882a593Smuzhiyun 			rt->rt_ttl_propagate == MPLS_TTL_PROP_ENABLED;
2016*4882a593Smuzhiyun 
2017*4882a593Smuzhiyun 		if (nla_put_u8(skb, RTA_TTL_PROPAGATE,
2018*4882a593Smuzhiyun 			       ttl_propagate))
2019*4882a593Smuzhiyun 			goto nla_put_failure;
2020*4882a593Smuzhiyun 	}
2021*4882a593Smuzhiyun 	if (rt->rt_nhn == 1) {
2022*4882a593Smuzhiyun 		const struct mpls_nh *nh = rt->rt_nh;
2023*4882a593Smuzhiyun 
2024*4882a593Smuzhiyun 		if (nh->nh_labels &&
2025*4882a593Smuzhiyun 		    nla_put_labels(skb, RTA_NEWDST, nh->nh_labels,
2026*4882a593Smuzhiyun 				   nh->nh_label))
2027*4882a593Smuzhiyun 			goto nla_put_failure;
2028*4882a593Smuzhiyun 		if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC &&
2029*4882a593Smuzhiyun 		    nla_put_via(skb, nh->nh_via_table, mpls_nh_via(rt, nh),
2030*4882a593Smuzhiyun 				nh->nh_via_alen))
2031*4882a593Smuzhiyun 			goto nla_put_failure;
2032*4882a593Smuzhiyun 		dev = rtnl_dereference(nh->nh_dev);
2033*4882a593Smuzhiyun 		if (dev && nla_put_u32(skb, RTA_OIF, dev->ifindex))
2034*4882a593Smuzhiyun 			goto nla_put_failure;
2035*4882a593Smuzhiyun 		if (nh->nh_flags & RTNH_F_LINKDOWN)
2036*4882a593Smuzhiyun 			rtm->rtm_flags |= RTNH_F_LINKDOWN;
2037*4882a593Smuzhiyun 		if (nh->nh_flags & RTNH_F_DEAD)
2038*4882a593Smuzhiyun 			rtm->rtm_flags |= RTNH_F_DEAD;
2039*4882a593Smuzhiyun 	} else {
2040*4882a593Smuzhiyun 		struct rtnexthop *rtnh;
2041*4882a593Smuzhiyun 		struct nlattr *mp;
2042*4882a593Smuzhiyun 		u8 linkdown = 0;
2043*4882a593Smuzhiyun 		u8 dead = 0;
2044*4882a593Smuzhiyun 
2045*4882a593Smuzhiyun 		mp = nla_nest_start_noflag(skb, RTA_MULTIPATH);
2046*4882a593Smuzhiyun 		if (!mp)
2047*4882a593Smuzhiyun 			goto nla_put_failure;
2048*4882a593Smuzhiyun 
2049*4882a593Smuzhiyun 		for_nexthops(rt) {
2050*4882a593Smuzhiyun 			dev = rtnl_dereference(nh->nh_dev);
2051*4882a593Smuzhiyun 			if (!dev)
2052*4882a593Smuzhiyun 				continue;
2053*4882a593Smuzhiyun 
2054*4882a593Smuzhiyun 			rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));
2055*4882a593Smuzhiyun 			if (!rtnh)
2056*4882a593Smuzhiyun 				goto nla_put_failure;
2057*4882a593Smuzhiyun 
2058*4882a593Smuzhiyun 			rtnh->rtnh_ifindex = dev->ifindex;
2059*4882a593Smuzhiyun 			if (nh->nh_flags & RTNH_F_LINKDOWN) {
2060*4882a593Smuzhiyun 				rtnh->rtnh_flags |= RTNH_F_LINKDOWN;
2061*4882a593Smuzhiyun 				linkdown++;
2062*4882a593Smuzhiyun 			}
2063*4882a593Smuzhiyun 			if (nh->nh_flags & RTNH_F_DEAD) {
2064*4882a593Smuzhiyun 				rtnh->rtnh_flags |= RTNH_F_DEAD;
2065*4882a593Smuzhiyun 				dead++;
2066*4882a593Smuzhiyun 			}
2067*4882a593Smuzhiyun 
2068*4882a593Smuzhiyun 			if (nh->nh_labels && nla_put_labels(skb, RTA_NEWDST,
2069*4882a593Smuzhiyun 							    nh->nh_labels,
2070*4882a593Smuzhiyun 							    nh->nh_label))
2071*4882a593Smuzhiyun 				goto nla_put_failure;
2072*4882a593Smuzhiyun 			if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC &&
2073*4882a593Smuzhiyun 			    nla_put_via(skb, nh->nh_via_table,
2074*4882a593Smuzhiyun 					mpls_nh_via(rt, nh),
2075*4882a593Smuzhiyun 					nh->nh_via_alen))
2076*4882a593Smuzhiyun 				goto nla_put_failure;
2077*4882a593Smuzhiyun 
2078*4882a593Smuzhiyun 			/* length of rtnetlink header + attributes */
2079*4882a593Smuzhiyun 			rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *)rtnh;
2080*4882a593Smuzhiyun 		} endfor_nexthops(rt);
2081*4882a593Smuzhiyun 
2082*4882a593Smuzhiyun 		if (linkdown == rt->rt_nhn)
2083*4882a593Smuzhiyun 			rtm->rtm_flags |= RTNH_F_LINKDOWN;
2084*4882a593Smuzhiyun 		if (dead == rt->rt_nhn)
2085*4882a593Smuzhiyun 			rtm->rtm_flags |= RTNH_F_DEAD;
2086*4882a593Smuzhiyun 
2087*4882a593Smuzhiyun 		nla_nest_end(skb, mp);
2088*4882a593Smuzhiyun 	}
2089*4882a593Smuzhiyun 
2090*4882a593Smuzhiyun 	nlmsg_end(skb, nlh);
2091*4882a593Smuzhiyun 	return 0;
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun nla_put_failure:
2094*4882a593Smuzhiyun 	nlmsg_cancel(skb, nlh);
2095*4882a593Smuzhiyun 	return -EMSGSIZE;
2096*4882a593Smuzhiyun }
2097*4882a593Smuzhiyun 
2098*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_INET)
mpls_valid_fib_dump_req(struct net * net,const struct nlmsghdr * nlh,struct fib_dump_filter * filter,struct netlink_callback * cb)2099*4882a593Smuzhiyun static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
2100*4882a593Smuzhiyun 				   struct fib_dump_filter *filter,
2101*4882a593Smuzhiyun 				   struct netlink_callback *cb)
2102*4882a593Smuzhiyun {
2103*4882a593Smuzhiyun 	return ip_valid_fib_dump_req(net, nlh, filter, cb);
2104*4882a593Smuzhiyun }
2105*4882a593Smuzhiyun #else
mpls_valid_fib_dump_req(struct net * net,const struct nlmsghdr * nlh,struct fib_dump_filter * filter,struct netlink_callback * cb)2106*4882a593Smuzhiyun static int mpls_valid_fib_dump_req(struct net *net, const struct nlmsghdr *nlh,
2107*4882a593Smuzhiyun 				   struct fib_dump_filter *filter,
2108*4882a593Smuzhiyun 				   struct netlink_callback *cb)
2109*4882a593Smuzhiyun {
2110*4882a593Smuzhiyun 	struct netlink_ext_ack *extack = cb->extack;
2111*4882a593Smuzhiyun 	struct nlattr *tb[RTA_MAX + 1];
2112*4882a593Smuzhiyun 	struct rtmsg *rtm;
2113*4882a593Smuzhiyun 	int err, i;
2114*4882a593Smuzhiyun 
2115*4882a593Smuzhiyun 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
2116*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Invalid header for FIB dump request");
2117*4882a593Smuzhiyun 		return -EINVAL;
2118*4882a593Smuzhiyun 	}
2119*4882a593Smuzhiyun 
2120*4882a593Smuzhiyun 	rtm = nlmsg_data(nlh);
2121*4882a593Smuzhiyun 	if (rtm->rtm_dst_len || rtm->rtm_src_len  || rtm->rtm_tos   ||
2122*4882a593Smuzhiyun 	    rtm->rtm_table   || rtm->rtm_scope    || rtm->rtm_type  ||
2123*4882a593Smuzhiyun 	    rtm->rtm_flags) {
2124*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for FIB dump request");
2125*4882a593Smuzhiyun 		return -EINVAL;
2126*4882a593Smuzhiyun 	}
2127*4882a593Smuzhiyun 
2128*4882a593Smuzhiyun 	if (rtm->rtm_protocol) {
2129*4882a593Smuzhiyun 		filter->protocol = rtm->rtm_protocol;
2130*4882a593Smuzhiyun 		filter->filter_set = 1;
2131*4882a593Smuzhiyun 		cb->answer_flags = NLM_F_DUMP_FILTERED;
2132*4882a593Smuzhiyun 	}
2133*4882a593Smuzhiyun 
2134*4882a593Smuzhiyun 	err = nlmsg_parse_deprecated_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
2135*4882a593Smuzhiyun 					    rtm_mpls_policy, extack);
2136*4882a593Smuzhiyun 	if (err < 0)
2137*4882a593Smuzhiyun 		return err;
2138*4882a593Smuzhiyun 
2139*4882a593Smuzhiyun 	for (i = 0; i <= RTA_MAX; ++i) {
2140*4882a593Smuzhiyun 		int ifindex;
2141*4882a593Smuzhiyun 
2142*4882a593Smuzhiyun 		if (i == RTA_OIF) {
2143*4882a593Smuzhiyun 			ifindex = nla_get_u32(tb[i]);
2144*4882a593Smuzhiyun 			filter->dev = __dev_get_by_index(net, ifindex);
2145*4882a593Smuzhiyun 			if (!filter->dev)
2146*4882a593Smuzhiyun 				return -ENODEV;
2147*4882a593Smuzhiyun 			filter->filter_set = 1;
2148*4882a593Smuzhiyun 		} else if (tb[i]) {
2149*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in dump request");
2150*4882a593Smuzhiyun 			return -EINVAL;
2151*4882a593Smuzhiyun 		}
2152*4882a593Smuzhiyun 	}
2153*4882a593Smuzhiyun 
2154*4882a593Smuzhiyun 	return 0;
2155*4882a593Smuzhiyun }
2156*4882a593Smuzhiyun #endif
2157*4882a593Smuzhiyun 
mpls_rt_uses_dev(struct mpls_route * rt,const struct net_device * dev)2158*4882a593Smuzhiyun static bool mpls_rt_uses_dev(struct mpls_route *rt,
2159*4882a593Smuzhiyun 			     const struct net_device *dev)
2160*4882a593Smuzhiyun {
2161*4882a593Smuzhiyun 	struct net_device *nh_dev;
2162*4882a593Smuzhiyun 
2163*4882a593Smuzhiyun 	if (rt->rt_nhn == 1) {
2164*4882a593Smuzhiyun 		struct mpls_nh *nh = rt->rt_nh;
2165*4882a593Smuzhiyun 
2166*4882a593Smuzhiyun 		nh_dev = rtnl_dereference(nh->nh_dev);
2167*4882a593Smuzhiyun 		if (dev == nh_dev)
2168*4882a593Smuzhiyun 			return true;
2169*4882a593Smuzhiyun 	} else {
2170*4882a593Smuzhiyun 		for_nexthops(rt) {
2171*4882a593Smuzhiyun 			nh_dev = rtnl_dereference(nh->nh_dev);
2172*4882a593Smuzhiyun 			if (nh_dev == dev)
2173*4882a593Smuzhiyun 				return true;
2174*4882a593Smuzhiyun 		} endfor_nexthops(rt);
2175*4882a593Smuzhiyun 	}
2176*4882a593Smuzhiyun 
2177*4882a593Smuzhiyun 	return false;
2178*4882a593Smuzhiyun }
2179*4882a593Smuzhiyun 
mpls_dump_routes(struct sk_buff * skb,struct netlink_callback * cb)2180*4882a593Smuzhiyun static int mpls_dump_routes(struct sk_buff *skb, struct netlink_callback *cb)
2181*4882a593Smuzhiyun {
2182*4882a593Smuzhiyun 	const struct nlmsghdr *nlh = cb->nlh;
2183*4882a593Smuzhiyun 	struct net *net = sock_net(skb->sk);
2184*4882a593Smuzhiyun 	struct mpls_route __rcu **platform_label;
2185*4882a593Smuzhiyun 	struct fib_dump_filter filter = {};
2186*4882a593Smuzhiyun 	unsigned int flags = NLM_F_MULTI;
2187*4882a593Smuzhiyun 	size_t platform_labels;
2188*4882a593Smuzhiyun 	unsigned int index;
2189*4882a593Smuzhiyun 
2190*4882a593Smuzhiyun 	ASSERT_RTNL();
2191*4882a593Smuzhiyun 
2192*4882a593Smuzhiyun 	if (cb->strict_check) {
2193*4882a593Smuzhiyun 		int err;
2194*4882a593Smuzhiyun 
2195*4882a593Smuzhiyun 		err = mpls_valid_fib_dump_req(net, nlh, &filter, cb);
2196*4882a593Smuzhiyun 		if (err < 0)
2197*4882a593Smuzhiyun 			return err;
2198*4882a593Smuzhiyun 
2199*4882a593Smuzhiyun 		/* for MPLS, there is only 1 table with fixed type and flags.
2200*4882a593Smuzhiyun 		 * If either are set in the filter then return nothing.
2201*4882a593Smuzhiyun 		 */
2202*4882a593Smuzhiyun 		if ((filter.table_id && filter.table_id != RT_TABLE_MAIN) ||
2203*4882a593Smuzhiyun 		    (filter.rt_type && filter.rt_type != RTN_UNICAST) ||
2204*4882a593Smuzhiyun 		     filter.flags)
2205*4882a593Smuzhiyun 			return skb->len;
2206*4882a593Smuzhiyun 	}
2207*4882a593Smuzhiyun 
2208*4882a593Smuzhiyun 	index = cb->args[0];
2209*4882a593Smuzhiyun 	if (index < MPLS_LABEL_FIRST_UNRESERVED)
2210*4882a593Smuzhiyun 		index = MPLS_LABEL_FIRST_UNRESERVED;
2211*4882a593Smuzhiyun 
2212*4882a593Smuzhiyun 	platform_label = rtnl_dereference(net->mpls.platform_label);
2213*4882a593Smuzhiyun 	platform_labels = net->mpls.platform_labels;
2214*4882a593Smuzhiyun 
2215*4882a593Smuzhiyun 	if (filter.filter_set)
2216*4882a593Smuzhiyun 		flags |= NLM_F_DUMP_FILTERED;
2217*4882a593Smuzhiyun 
2218*4882a593Smuzhiyun 	for (; index < platform_labels; index++) {
2219*4882a593Smuzhiyun 		struct mpls_route *rt;
2220*4882a593Smuzhiyun 
2221*4882a593Smuzhiyun 		rt = rtnl_dereference(platform_label[index]);
2222*4882a593Smuzhiyun 		if (!rt)
2223*4882a593Smuzhiyun 			continue;
2224*4882a593Smuzhiyun 
2225*4882a593Smuzhiyun 		if ((filter.dev && !mpls_rt_uses_dev(rt, filter.dev)) ||
2226*4882a593Smuzhiyun 		    (filter.protocol && rt->rt_protocol != filter.protocol))
2227*4882a593Smuzhiyun 			continue;
2228*4882a593Smuzhiyun 
2229*4882a593Smuzhiyun 		if (mpls_dump_route(skb, NETLINK_CB(cb->skb).portid,
2230*4882a593Smuzhiyun 				    cb->nlh->nlmsg_seq, RTM_NEWROUTE,
2231*4882a593Smuzhiyun 				    index, rt, flags) < 0)
2232*4882a593Smuzhiyun 			break;
2233*4882a593Smuzhiyun 	}
2234*4882a593Smuzhiyun 	cb->args[0] = index;
2235*4882a593Smuzhiyun 
2236*4882a593Smuzhiyun 	return skb->len;
2237*4882a593Smuzhiyun }
2238*4882a593Smuzhiyun 
lfib_nlmsg_size(struct mpls_route * rt)2239*4882a593Smuzhiyun static inline size_t lfib_nlmsg_size(struct mpls_route *rt)
2240*4882a593Smuzhiyun {
2241*4882a593Smuzhiyun 	size_t payload =
2242*4882a593Smuzhiyun 		NLMSG_ALIGN(sizeof(struct rtmsg))
2243*4882a593Smuzhiyun 		+ nla_total_size(4)			/* RTA_DST */
2244*4882a593Smuzhiyun 		+ nla_total_size(1);			/* RTA_TTL_PROPAGATE */
2245*4882a593Smuzhiyun 
2246*4882a593Smuzhiyun 	if (rt->rt_nhn == 1) {
2247*4882a593Smuzhiyun 		struct mpls_nh *nh = rt->rt_nh;
2248*4882a593Smuzhiyun 
2249*4882a593Smuzhiyun 		if (nh->nh_dev)
2250*4882a593Smuzhiyun 			payload += nla_total_size(4); /* RTA_OIF */
2251*4882a593Smuzhiyun 		if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC) /* RTA_VIA */
2252*4882a593Smuzhiyun 			payload += nla_total_size(2 + nh->nh_via_alen);
2253*4882a593Smuzhiyun 		if (nh->nh_labels) /* RTA_NEWDST */
2254*4882a593Smuzhiyun 			payload += nla_total_size(nh->nh_labels * 4);
2255*4882a593Smuzhiyun 	} else {
2256*4882a593Smuzhiyun 		/* each nexthop is packed in an attribute */
2257*4882a593Smuzhiyun 		size_t nhsize = 0;
2258*4882a593Smuzhiyun 
2259*4882a593Smuzhiyun 		for_nexthops(rt) {
2260*4882a593Smuzhiyun 			if (!rtnl_dereference(nh->nh_dev))
2261*4882a593Smuzhiyun 				continue;
2262*4882a593Smuzhiyun 			nhsize += nla_total_size(sizeof(struct rtnexthop));
2263*4882a593Smuzhiyun 			/* RTA_VIA */
2264*4882a593Smuzhiyun 			if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC)
2265*4882a593Smuzhiyun 				nhsize += nla_total_size(2 + nh->nh_via_alen);
2266*4882a593Smuzhiyun 			if (nh->nh_labels)
2267*4882a593Smuzhiyun 				nhsize += nla_total_size(nh->nh_labels * 4);
2268*4882a593Smuzhiyun 		} endfor_nexthops(rt);
2269*4882a593Smuzhiyun 		/* nested attribute */
2270*4882a593Smuzhiyun 		payload += nla_total_size(nhsize);
2271*4882a593Smuzhiyun 	}
2272*4882a593Smuzhiyun 
2273*4882a593Smuzhiyun 	return payload;
2274*4882a593Smuzhiyun }
2275*4882a593Smuzhiyun 
rtmsg_lfib(int event,u32 label,struct mpls_route * rt,struct nlmsghdr * nlh,struct net * net,u32 portid,unsigned int nlm_flags)2276*4882a593Smuzhiyun static void rtmsg_lfib(int event, u32 label, struct mpls_route *rt,
2277*4882a593Smuzhiyun 		       struct nlmsghdr *nlh, struct net *net, u32 portid,
2278*4882a593Smuzhiyun 		       unsigned int nlm_flags)
2279*4882a593Smuzhiyun {
2280*4882a593Smuzhiyun 	struct sk_buff *skb;
2281*4882a593Smuzhiyun 	u32 seq = nlh ? nlh->nlmsg_seq : 0;
2282*4882a593Smuzhiyun 	int err = -ENOBUFS;
2283*4882a593Smuzhiyun 
2284*4882a593Smuzhiyun 	skb = nlmsg_new(lfib_nlmsg_size(rt), GFP_KERNEL);
2285*4882a593Smuzhiyun 	if (skb == NULL)
2286*4882a593Smuzhiyun 		goto errout;
2287*4882a593Smuzhiyun 
2288*4882a593Smuzhiyun 	err = mpls_dump_route(skb, portid, seq, event, label, rt, nlm_flags);
2289*4882a593Smuzhiyun 	if (err < 0) {
2290*4882a593Smuzhiyun 		/* -EMSGSIZE implies BUG in lfib_nlmsg_size */
2291*4882a593Smuzhiyun 		WARN_ON(err == -EMSGSIZE);
2292*4882a593Smuzhiyun 		kfree_skb(skb);
2293*4882a593Smuzhiyun 		goto errout;
2294*4882a593Smuzhiyun 	}
2295*4882a593Smuzhiyun 	rtnl_notify(skb, net, portid, RTNLGRP_MPLS_ROUTE, nlh, GFP_KERNEL);
2296*4882a593Smuzhiyun 
2297*4882a593Smuzhiyun 	return;
2298*4882a593Smuzhiyun errout:
2299*4882a593Smuzhiyun 	if (err < 0)
2300*4882a593Smuzhiyun 		rtnl_set_sk_err(net, RTNLGRP_MPLS_ROUTE, err);
2301*4882a593Smuzhiyun }
2302*4882a593Smuzhiyun 
mpls_valid_getroute_req(struct sk_buff * skb,const struct nlmsghdr * nlh,struct nlattr ** tb,struct netlink_ext_ack * extack)2303*4882a593Smuzhiyun static int mpls_valid_getroute_req(struct sk_buff *skb,
2304*4882a593Smuzhiyun 				   const struct nlmsghdr *nlh,
2305*4882a593Smuzhiyun 				   struct nlattr **tb,
2306*4882a593Smuzhiyun 				   struct netlink_ext_ack *extack)
2307*4882a593Smuzhiyun {
2308*4882a593Smuzhiyun 	struct rtmsg *rtm;
2309*4882a593Smuzhiyun 	int i, err;
2310*4882a593Smuzhiyun 
2311*4882a593Smuzhiyun 	if (nlh->nlmsg_len < nlmsg_msg_size(sizeof(*rtm))) {
2312*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack,
2313*4882a593Smuzhiyun 				   "Invalid header for get route request");
2314*4882a593Smuzhiyun 		return -EINVAL;
2315*4882a593Smuzhiyun 	}
2316*4882a593Smuzhiyun 
2317*4882a593Smuzhiyun 	if (!netlink_strict_get_check(skb))
2318*4882a593Smuzhiyun 		return nlmsg_parse_deprecated(nlh, sizeof(*rtm), tb, RTA_MAX,
2319*4882a593Smuzhiyun 					      rtm_mpls_policy, extack);
2320*4882a593Smuzhiyun 
2321*4882a593Smuzhiyun 	rtm = nlmsg_data(nlh);
2322*4882a593Smuzhiyun 	if ((rtm->rtm_dst_len && rtm->rtm_dst_len != 20) ||
2323*4882a593Smuzhiyun 	    rtm->rtm_src_len || rtm->rtm_tos || rtm->rtm_table ||
2324*4882a593Smuzhiyun 	    rtm->rtm_protocol || rtm->rtm_scope || rtm->rtm_type) {
2325*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "Invalid values in header for get route request");
2326*4882a593Smuzhiyun 		return -EINVAL;
2327*4882a593Smuzhiyun 	}
2328*4882a593Smuzhiyun 	if (rtm->rtm_flags & ~RTM_F_FIB_MATCH) {
2329*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack,
2330*4882a593Smuzhiyun 				   "Invalid flags for get route request");
2331*4882a593Smuzhiyun 		return -EINVAL;
2332*4882a593Smuzhiyun 	}
2333*4882a593Smuzhiyun 
2334*4882a593Smuzhiyun 	err = nlmsg_parse_deprecated_strict(nlh, sizeof(*rtm), tb, RTA_MAX,
2335*4882a593Smuzhiyun 					    rtm_mpls_policy, extack);
2336*4882a593Smuzhiyun 	if (err)
2337*4882a593Smuzhiyun 		return err;
2338*4882a593Smuzhiyun 
2339*4882a593Smuzhiyun 	if ((tb[RTA_DST] || tb[RTA_NEWDST]) && !rtm->rtm_dst_len) {
2340*4882a593Smuzhiyun 		NL_SET_ERR_MSG_MOD(extack, "rtm_dst_len must be 20 for MPLS");
2341*4882a593Smuzhiyun 		return -EINVAL;
2342*4882a593Smuzhiyun 	}
2343*4882a593Smuzhiyun 
2344*4882a593Smuzhiyun 	for (i = 0; i <= RTA_MAX; i++) {
2345*4882a593Smuzhiyun 		if (!tb[i])
2346*4882a593Smuzhiyun 			continue;
2347*4882a593Smuzhiyun 
2348*4882a593Smuzhiyun 		switch (i) {
2349*4882a593Smuzhiyun 		case RTA_DST:
2350*4882a593Smuzhiyun 		case RTA_NEWDST:
2351*4882a593Smuzhiyun 			break;
2352*4882a593Smuzhiyun 		default:
2353*4882a593Smuzhiyun 			NL_SET_ERR_MSG_MOD(extack, "Unsupported attribute in get route request");
2354*4882a593Smuzhiyun 			return -EINVAL;
2355*4882a593Smuzhiyun 		}
2356*4882a593Smuzhiyun 	}
2357*4882a593Smuzhiyun 
2358*4882a593Smuzhiyun 	return 0;
2359*4882a593Smuzhiyun }
2360*4882a593Smuzhiyun 
mpls_getroute(struct sk_buff * in_skb,struct nlmsghdr * in_nlh,struct netlink_ext_ack * extack)2361*4882a593Smuzhiyun static int mpls_getroute(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
2362*4882a593Smuzhiyun 			 struct netlink_ext_ack *extack)
2363*4882a593Smuzhiyun {
2364*4882a593Smuzhiyun 	struct net *net = sock_net(in_skb->sk);
2365*4882a593Smuzhiyun 	u32 portid = NETLINK_CB(in_skb).portid;
2366*4882a593Smuzhiyun 	u32 in_label = LABEL_NOT_SPECIFIED;
2367*4882a593Smuzhiyun 	struct nlattr *tb[RTA_MAX + 1];
2368*4882a593Smuzhiyun 	u32 labels[MAX_NEW_LABELS];
2369*4882a593Smuzhiyun 	struct mpls_shim_hdr *hdr;
2370*4882a593Smuzhiyun 	unsigned int hdr_size = 0;
2371*4882a593Smuzhiyun 	struct net_device *dev;
2372*4882a593Smuzhiyun 	struct mpls_route *rt;
2373*4882a593Smuzhiyun 	struct rtmsg *rtm, *r;
2374*4882a593Smuzhiyun 	struct nlmsghdr *nlh;
2375*4882a593Smuzhiyun 	struct sk_buff *skb;
2376*4882a593Smuzhiyun 	struct mpls_nh *nh;
2377*4882a593Smuzhiyun 	u8 n_labels;
2378*4882a593Smuzhiyun 	int err;
2379*4882a593Smuzhiyun 
2380*4882a593Smuzhiyun 	err = mpls_valid_getroute_req(in_skb, in_nlh, tb, extack);
2381*4882a593Smuzhiyun 	if (err < 0)
2382*4882a593Smuzhiyun 		goto errout;
2383*4882a593Smuzhiyun 
2384*4882a593Smuzhiyun 	rtm = nlmsg_data(in_nlh);
2385*4882a593Smuzhiyun 
2386*4882a593Smuzhiyun 	if (tb[RTA_DST]) {
2387*4882a593Smuzhiyun 		u8 label_count;
2388*4882a593Smuzhiyun 
2389*4882a593Smuzhiyun 		if (nla_get_labels(tb[RTA_DST], 1, &label_count,
2390*4882a593Smuzhiyun 				   &in_label, extack)) {
2391*4882a593Smuzhiyun 			err = -EINVAL;
2392*4882a593Smuzhiyun 			goto errout;
2393*4882a593Smuzhiyun 		}
2394*4882a593Smuzhiyun 
2395*4882a593Smuzhiyun 		if (!mpls_label_ok(net, &in_label, extack)) {
2396*4882a593Smuzhiyun 			err = -EINVAL;
2397*4882a593Smuzhiyun 			goto errout;
2398*4882a593Smuzhiyun 		}
2399*4882a593Smuzhiyun 	}
2400*4882a593Smuzhiyun 
2401*4882a593Smuzhiyun 	rt = mpls_route_input_rcu(net, in_label);
2402*4882a593Smuzhiyun 	if (!rt) {
2403*4882a593Smuzhiyun 		err = -ENETUNREACH;
2404*4882a593Smuzhiyun 		goto errout;
2405*4882a593Smuzhiyun 	}
2406*4882a593Smuzhiyun 
2407*4882a593Smuzhiyun 	if (rtm->rtm_flags & RTM_F_FIB_MATCH) {
2408*4882a593Smuzhiyun 		skb = nlmsg_new(lfib_nlmsg_size(rt), GFP_KERNEL);
2409*4882a593Smuzhiyun 		if (!skb) {
2410*4882a593Smuzhiyun 			err = -ENOBUFS;
2411*4882a593Smuzhiyun 			goto errout;
2412*4882a593Smuzhiyun 		}
2413*4882a593Smuzhiyun 
2414*4882a593Smuzhiyun 		err = mpls_dump_route(skb, portid, in_nlh->nlmsg_seq,
2415*4882a593Smuzhiyun 				      RTM_NEWROUTE, in_label, rt, 0);
2416*4882a593Smuzhiyun 		if (err < 0) {
2417*4882a593Smuzhiyun 			/* -EMSGSIZE implies BUG in lfib_nlmsg_size */
2418*4882a593Smuzhiyun 			WARN_ON(err == -EMSGSIZE);
2419*4882a593Smuzhiyun 			goto errout_free;
2420*4882a593Smuzhiyun 		}
2421*4882a593Smuzhiyun 
2422*4882a593Smuzhiyun 		return rtnl_unicast(skb, net, portid);
2423*4882a593Smuzhiyun 	}
2424*4882a593Smuzhiyun 
2425*4882a593Smuzhiyun 	if (tb[RTA_NEWDST]) {
2426*4882a593Smuzhiyun 		if (nla_get_labels(tb[RTA_NEWDST], MAX_NEW_LABELS, &n_labels,
2427*4882a593Smuzhiyun 				   labels, extack) != 0) {
2428*4882a593Smuzhiyun 			err = -EINVAL;
2429*4882a593Smuzhiyun 			goto errout;
2430*4882a593Smuzhiyun 		}
2431*4882a593Smuzhiyun 
2432*4882a593Smuzhiyun 		hdr_size = n_labels * sizeof(struct mpls_shim_hdr);
2433*4882a593Smuzhiyun 	}
2434*4882a593Smuzhiyun 
2435*4882a593Smuzhiyun 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
2436*4882a593Smuzhiyun 	if (!skb) {
2437*4882a593Smuzhiyun 		err = -ENOBUFS;
2438*4882a593Smuzhiyun 		goto errout;
2439*4882a593Smuzhiyun 	}
2440*4882a593Smuzhiyun 
2441*4882a593Smuzhiyun 	skb->protocol = htons(ETH_P_MPLS_UC);
2442*4882a593Smuzhiyun 
2443*4882a593Smuzhiyun 	if (hdr_size) {
2444*4882a593Smuzhiyun 		bool bos;
2445*4882a593Smuzhiyun 		int i;
2446*4882a593Smuzhiyun 
2447*4882a593Smuzhiyun 		if (skb_cow(skb, hdr_size)) {
2448*4882a593Smuzhiyun 			err = -ENOBUFS;
2449*4882a593Smuzhiyun 			goto errout_free;
2450*4882a593Smuzhiyun 		}
2451*4882a593Smuzhiyun 
2452*4882a593Smuzhiyun 		skb_reserve(skb, hdr_size);
2453*4882a593Smuzhiyun 		skb_push(skb, hdr_size);
2454*4882a593Smuzhiyun 		skb_reset_network_header(skb);
2455*4882a593Smuzhiyun 
2456*4882a593Smuzhiyun 		/* Push new labels */
2457*4882a593Smuzhiyun 		hdr = mpls_hdr(skb);
2458*4882a593Smuzhiyun 		bos = true;
2459*4882a593Smuzhiyun 		for (i = n_labels - 1; i >= 0; i--) {
2460*4882a593Smuzhiyun 			hdr[i] = mpls_entry_encode(labels[i],
2461*4882a593Smuzhiyun 						   1, 0, bos);
2462*4882a593Smuzhiyun 			bos = false;
2463*4882a593Smuzhiyun 		}
2464*4882a593Smuzhiyun 	}
2465*4882a593Smuzhiyun 
2466*4882a593Smuzhiyun 	nh = mpls_select_multipath(rt, skb);
2467*4882a593Smuzhiyun 	if (!nh) {
2468*4882a593Smuzhiyun 		err = -ENETUNREACH;
2469*4882a593Smuzhiyun 		goto errout_free;
2470*4882a593Smuzhiyun 	}
2471*4882a593Smuzhiyun 
2472*4882a593Smuzhiyun 	if (hdr_size) {
2473*4882a593Smuzhiyun 		skb_pull(skb, hdr_size);
2474*4882a593Smuzhiyun 		skb_reset_network_header(skb);
2475*4882a593Smuzhiyun 	}
2476*4882a593Smuzhiyun 
2477*4882a593Smuzhiyun 	nlh = nlmsg_put(skb, portid, in_nlh->nlmsg_seq,
2478*4882a593Smuzhiyun 			RTM_NEWROUTE, sizeof(*r), 0);
2479*4882a593Smuzhiyun 	if (!nlh) {
2480*4882a593Smuzhiyun 		err = -EMSGSIZE;
2481*4882a593Smuzhiyun 		goto errout_free;
2482*4882a593Smuzhiyun 	}
2483*4882a593Smuzhiyun 
2484*4882a593Smuzhiyun 	r = nlmsg_data(nlh);
2485*4882a593Smuzhiyun 	r->rtm_family	 = AF_MPLS;
2486*4882a593Smuzhiyun 	r->rtm_dst_len	= 20;
2487*4882a593Smuzhiyun 	r->rtm_src_len	= 0;
2488*4882a593Smuzhiyun 	r->rtm_table	= RT_TABLE_MAIN;
2489*4882a593Smuzhiyun 	r->rtm_type	= RTN_UNICAST;
2490*4882a593Smuzhiyun 	r->rtm_scope	= RT_SCOPE_UNIVERSE;
2491*4882a593Smuzhiyun 	r->rtm_protocol = rt->rt_protocol;
2492*4882a593Smuzhiyun 	r->rtm_flags	= 0;
2493*4882a593Smuzhiyun 
2494*4882a593Smuzhiyun 	if (nla_put_labels(skb, RTA_DST, 1, &in_label))
2495*4882a593Smuzhiyun 		goto nla_put_failure;
2496*4882a593Smuzhiyun 
2497*4882a593Smuzhiyun 	if (nh->nh_labels &&
2498*4882a593Smuzhiyun 	    nla_put_labels(skb, RTA_NEWDST, nh->nh_labels,
2499*4882a593Smuzhiyun 			   nh->nh_label))
2500*4882a593Smuzhiyun 		goto nla_put_failure;
2501*4882a593Smuzhiyun 
2502*4882a593Smuzhiyun 	if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC &&
2503*4882a593Smuzhiyun 	    nla_put_via(skb, nh->nh_via_table, mpls_nh_via(rt, nh),
2504*4882a593Smuzhiyun 			nh->nh_via_alen))
2505*4882a593Smuzhiyun 		goto nla_put_failure;
2506*4882a593Smuzhiyun 	dev = rtnl_dereference(nh->nh_dev);
2507*4882a593Smuzhiyun 	if (dev && nla_put_u32(skb, RTA_OIF, dev->ifindex))
2508*4882a593Smuzhiyun 		goto nla_put_failure;
2509*4882a593Smuzhiyun 
2510*4882a593Smuzhiyun 	nlmsg_end(skb, nlh);
2511*4882a593Smuzhiyun 
2512*4882a593Smuzhiyun 	err = rtnl_unicast(skb, net, portid);
2513*4882a593Smuzhiyun errout:
2514*4882a593Smuzhiyun 	return err;
2515*4882a593Smuzhiyun 
2516*4882a593Smuzhiyun nla_put_failure:
2517*4882a593Smuzhiyun 	nlmsg_cancel(skb, nlh);
2518*4882a593Smuzhiyun 	err = -EMSGSIZE;
2519*4882a593Smuzhiyun errout_free:
2520*4882a593Smuzhiyun 	kfree_skb(skb);
2521*4882a593Smuzhiyun 	return err;
2522*4882a593Smuzhiyun }
2523*4882a593Smuzhiyun 
resize_platform_label_table(struct net * net,size_t limit)2524*4882a593Smuzhiyun static int resize_platform_label_table(struct net *net, size_t limit)
2525*4882a593Smuzhiyun {
2526*4882a593Smuzhiyun 	size_t size = sizeof(struct mpls_route *) * limit;
2527*4882a593Smuzhiyun 	size_t old_limit;
2528*4882a593Smuzhiyun 	size_t cp_size;
2529*4882a593Smuzhiyun 	struct mpls_route __rcu **labels = NULL, **old;
2530*4882a593Smuzhiyun 	struct mpls_route *rt0 = NULL, *rt2 = NULL;
2531*4882a593Smuzhiyun 	unsigned index;
2532*4882a593Smuzhiyun 
2533*4882a593Smuzhiyun 	if (size) {
2534*4882a593Smuzhiyun 		labels = kvzalloc(size, GFP_KERNEL);
2535*4882a593Smuzhiyun 		if (!labels)
2536*4882a593Smuzhiyun 			goto nolabels;
2537*4882a593Smuzhiyun 	}
2538*4882a593Smuzhiyun 
2539*4882a593Smuzhiyun 	/* In case the predefined labels need to be populated */
2540*4882a593Smuzhiyun 	if (limit > MPLS_LABEL_IPV4NULL) {
2541*4882a593Smuzhiyun 		struct net_device *lo = net->loopback_dev;
2542*4882a593Smuzhiyun 		rt0 = mpls_rt_alloc(1, lo->addr_len, 0);
2543*4882a593Smuzhiyun 		if (IS_ERR(rt0))
2544*4882a593Smuzhiyun 			goto nort0;
2545*4882a593Smuzhiyun 		RCU_INIT_POINTER(rt0->rt_nh->nh_dev, lo);
2546*4882a593Smuzhiyun 		rt0->rt_protocol = RTPROT_KERNEL;
2547*4882a593Smuzhiyun 		rt0->rt_payload_type = MPT_IPV4;
2548*4882a593Smuzhiyun 		rt0->rt_ttl_propagate = MPLS_TTL_PROP_DEFAULT;
2549*4882a593Smuzhiyun 		rt0->rt_nh->nh_via_table = NEIGH_LINK_TABLE;
2550*4882a593Smuzhiyun 		rt0->rt_nh->nh_via_alen = lo->addr_len;
2551*4882a593Smuzhiyun 		memcpy(__mpls_nh_via(rt0, rt0->rt_nh), lo->dev_addr,
2552*4882a593Smuzhiyun 		       lo->addr_len);
2553*4882a593Smuzhiyun 	}
2554*4882a593Smuzhiyun 	if (limit > MPLS_LABEL_IPV6NULL) {
2555*4882a593Smuzhiyun 		struct net_device *lo = net->loopback_dev;
2556*4882a593Smuzhiyun 		rt2 = mpls_rt_alloc(1, lo->addr_len, 0);
2557*4882a593Smuzhiyun 		if (IS_ERR(rt2))
2558*4882a593Smuzhiyun 			goto nort2;
2559*4882a593Smuzhiyun 		RCU_INIT_POINTER(rt2->rt_nh->nh_dev, lo);
2560*4882a593Smuzhiyun 		rt2->rt_protocol = RTPROT_KERNEL;
2561*4882a593Smuzhiyun 		rt2->rt_payload_type = MPT_IPV6;
2562*4882a593Smuzhiyun 		rt2->rt_ttl_propagate = MPLS_TTL_PROP_DEFAULT;
2563*4882a593Smuzhiyun 		rt2->rt_nh->nh_via_table = NEIGH_LINK_TABLE;
2564*4882a593Smuzhiyun 		rt2->rt_nh->nh_via_alen = lo->addr_len;
2565*4882a593Smuzhiyun 		memcpy(__mpls_nh_via(rt2, rt2->rt_nh), lo->dev_addr,
2566*4882a593Smuzhiyun 		       lo->addr_len);
2567*4882a593Smuzhiyun 	}
2568*4882a593Smuzhiyun 
2569*4882a593Smuzhiyun 	rtnl_lock();
2570*4882a593Smuzhiyun 	/* Remember the original table */
2571*4882a593Smuzhiyun 	old = rtnl_dereference(net->mpls.platform_label);
2572*4882a593Smuzhiyun 	old_limit = net->mpls.platform_labels;
2573*4882a593Smuzhiyun 
2574*4882a593Smuzhiyun 	/* Free any labels beyond the new table */
2575*4882a593Smuzhiyun 	for (index = limit; index < old_limit; index++)
2576*4882a593Smuzhiyun 		mpls_route_update(net, index, NULL, NULL);
2577*4882a593Smuzhiyun 
2578*4882a593Smuzhiyun 	/* Copy over the old labels */
2579*4882a593Smuzhiyun 	cp_size = size;
2580*4882a593Smuzhiyun 	if (old_limit < limit)
2581*4882a593Smuzhiyun 		cp_size = old_limit * sizeof(struct mpls_route *);
2582*4882a593Smuzhiyun 
2583*4882a593Smuzhiyun 	memcpy(labels, old, cp_size);
2584*4882a593Smuzhiyun 
2585*4882a593Smuzhiyun 	/* If needed set the predefined labels */
2586*4882a593Smuzhiyun 	if ((old_limit <= MPLS_LABEL_IPV6NULL) &&
2587*4882a593Smuzhiyun 	    (limit > MPLS_LABEL_IPV6NULL)) {
2588*4882a593Smuzhiyun 		RCU_INIT_POINTER(labels[MPLS_LABEL_IPV6NULL], rt2);
2589*4882a593Smuzhiyun 		rt2 = NULL;
2590*4882a593Smuzhiyun 	}
2591*4882a593Smuzhiyun 
2592*4882a593Smuzhiyun 	if ((old_limit <= MPLS_LABEL_IPV4NULL) &&
2593*4882a593Smuzhiyun 	    (limit > MPLS_LABEL_IPV4NULL)) {
2594*4882a593Smuzhiyun 		RCU_INIT_POINTER(labels[MPLS_LABEL_IPV4NULL], rt0);
2595*4882a593Smuzhiyun 		rt0 = NULL;
2596*4882a593Smuzhiyun 	}
2597*4882a593Smuzhiyun 
2598*4882a593Smuzhiyun 	/* Update the global pointers */
2599*4882a593Smuzhiyun 	net->mpls.platform_labels = limit;
2600*4882a593Smuzhiyun 	rcu_assign_pointer(net->mpls.platform_label, labels);
2601*4882a593Smuzhiyun 
2602*4882a593Smuzhiyun 	rtnl_unlock();
2603*4882a593Smuzhiyun 
2604*4882a593Smuzhiyun 	mpls_rt_free(rt2);
2605*4882a593Smuzhiyun 	mpls_rt_free(rt0);
2606*4882a593Smuzhiyun 
2607*4882a593Smuzhiyun 	if (old) {
2608*4882a593Smuzhiyun 		synchronize_rcu();
2609*4882a593Smuzhiyun 		kvfree(old);
2610*4882a593Smuzhiyun 	}
2611*4882a593Smuzhiyun 	return 0;
2612*4882a593Smuzhiyun 
2613*4882a593Smuzhiyun nort2:
2614*4882a593Smuzhiyun 	mpls_rt_free(rt0);
2615*4882a593Smuzhiyun nort0:
2616*4882a593Smuzhiyun 	kvfree(labels);
2617*4882a593Smuzhiyun nolabels:
2618*4882a593Smuzhiyun 	return -ENOMEM;
2619*4882a593Smuzhiyun }
2620*4882a593Smuzhiyun 
mpls_platform_labels(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)2621*4882a593Smuzhiyun static int mpls_platform_labels(struct ctl_table *table, int write,
2622*4882a593Smuzhiyun 				void *buffer, size_t *lenp, loff_t *ppos)
2623*4882a593Smuzhiyun {
2624*4882a593Smuzhiyun 	struct net *net = table->data;
2625*4882a593Smuzhiyun 	int platform_labels = net->mpls.platform_labels;
2626*4882a593Smuzhiyun 	int ret;
2627*4882a593Smuzhiyun 	struct ctl_table tmp = {
2628*4882a593Smuzhiyun 		.procname	= table->procname,
2629*4882a593Smuzhiyun 		.data		= &platform_labels,
2630*4882a593Smuzhiyun 		.maxlen		= sizeof(int),
2631*4882a593Smuzhiyun 		.mode		= table->mode,
2632*4882a593Smuzhiyun 		.extra1		= SYSCTL_ZERO,
2633*4882a593Smuzhiyun 		.extra2		= &label_limit,
2634*4882a593Smuzhiyun 	};
2635*4882a593Smuzhiyun 
2636*4882a593Smuzhiyun 	ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
2637*4882a593Smuzhiyun 
2638*4882a593Smuzhiyun 	if (write && ret == 0)
2639*4882a593Smuzhiyun 		ret = resize_platform_label_table(net, platform_labels);
2640*4882a593Smuzhiyun 
2641*4882a593Smuzhiyun 	return ret;
2642*4882a593Smuzhiyun }
2643*4882a593Smuzhiyun 
2644*4882a593Smuzhiyun #define MPLS_NS_SYSCTL_OFFSET(field)		\
2645*4882a593Smuzhiyun 	(&((struct net *)0)->field)
2646*4882a593Smuzhiyun 
2647*4882a593Smuzhiyun static const struct ctl_table mpls_table[] = {
2648*4882a593Smuzhiyun 	{
2649*4882a593Smuzhiyun 		.procname	= "platform_labels",
2650*4882a593Smuzhiyun 		.data		= NULL,
2651*4882a593Smuzhiyun 		.maxlen		= sizeof(int),
2652*4882a593Smuzhiyun 		.mode		= 0644,
2653*4882a593Smuzhiyun 		.proc_handler	= mpls_platform_labels,
2654*4882a593Smuzhiyun 	},
2655*4882a593Smuzhiyun 	{
2656*4882a593Smuzhiyun 		.procname	= "ip_ttl_propagate",
2657*4882a593Smuzhiyun 		.data		= MPLS_NS_SYSCTL_OFFSET(mpls.ip_ttl_propagate),
2658*4882a593Smuzhiyun 		.maxlen		= sizeof(int),
2659*4882a593Smuzhiyun 		.mode		= 0644,
2660*4882a593Smuzhiyun 		.proc_handler	= proc_dointvec_minmax,
2661*4882a593Smuzhiyun 		.extra1		= SYSCTL_ZERO,
2662*4882a593Smuzhiyun 		.extra2		= SYSCTL_ONE,
2663*4882a593Smuzhiyun 	},
2664*4882a593Smuzhiyun 	{
2665*4882a593Smuzhiyun 		.procname	= "default_ttl",
2666*4882a593Smuzhiyun 		.data		= MPLS_NS_SYSCTL_OFFSET(mpls.default_ttl),
2667*4882a593Smuzhiyun 		.maxlen		= sizeof(int),
2668*4882a593Smuzhiyun 		.mode		= 0644,
2669*4882a593Smuzhiyun 		.proc_handler	= proc_dointvec_minmax,
2670*4882a593Smuzhiyun 		.extra1		= SYSCTL_ONE,
2671*4882a593Smuzhiyun 		.extra2		= &ttl_max,
2672*4882a593Smuzhiyun 	},
2673*4882a593Smuzhiyun 	{ }
2674*4882a593Smuzhiyun };
2675*4882a593Smuzhiyun 
mpls_net_init(struct net * net)2676*4882a593Smuzhiyun static int mpls_net_init(struct net *net)
2677*4882a593Smuzhiyun {
2678*4882a593Smuzhiyun 	struct ctl_table *table;
2679*4882a593Smuzhiyun 	int i;
2680*4882a593Smuzhiyun 
2681*4882a593Smuzhiyun 	net->mpls.platform_labels = 0;
2682*4882a593Smuzhiyun 	net->mpls.platform_label = NULL;
2683*4882a593Smuzhiyun 	net->mpls.ip_ttl_propagate = 1;
2684*4882a593Smuzhiyun 	net->mpls.default_ttl = 255;
2685*4882a593Smuzhiyun 
2686*4882a593Smuzhiyun 	table = kmemdup(mpls_table, sizeof(mpls_table), GFP_KERNEL);
2687*4882a593Smuzhiyun 	if (table == NULL)
2688*4882a593Smuzhiyun 		return -ENOMEM;
2689*4882a593Smuzhiyun 
2690*4882a593Smuzhiyun 	/* Table data contains only offsets relative to the base of
2691*4882a593Smuzhiyun 	 * the mdev at this point, so make them absolute.
2692*4882a593Smuzhiyun 	 */
2693*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(mpls_table) - 1; i++)
2694*4882a593Smuzhiyun 		table[i].data = (char *)net + (uintptr_t)table[i].data;
2695*4882a593Smuzhiyun 
2696*4882a593Smuzhiyun 	net->mpls.ctl = register_net_sysctl(net, "net/mpls", table);
2697*4882a593Smuzhiyun 	if (net->mpls.ctl == NULL) {
2698*4882a593Smuzhiyun 		kfree(table);
2699*4882a593Smuzhiyun 		return -ENOMEM;
2700*4882a593Smuzhiyun 	}
2701*4882a593Smuzhiyun 
2702*4882a593Smuzhiyun 	return 0;
2703*4882a593Smuzhiyun }
2704*4882a593Smuzhiyun 
mpls_net_exit(struct net * net)2705*4882a593Smuzhiyun static void mpls_net_exit(struct net *net)
2706*4882a593Smuzhiyun {
2707*4882a593Smuzhiyun 	struct mpls_route __rcu **platform_label;
2708*4882a593Smuzhiyun 	size_t platform_labels;
2709*4882a593Smuzhiyun 	struct ctl_table *table;
2710*4882a593Smuzhiyun 	unsigned int index;
2711*4882a593Smuzhiyun 
2712*4882a593Smuzhiyun 	table = net->mpls.ctl->ctl_table_arg;
2713*4882a593Smuzhiyun 	unregister_net_sysctl_table(net->mpls.ctl);
2714*4882a593Smuzhiyun 	kfree(table);
2715*4882a593Smuzhiyun 
2716*4882a593Smuzhiyun 	/* An rcu grace period has passed since there was a device in
2717*4882a593Smuzhiyun 	 * the network namespace (and thus the last in flight packet)
2718*4882a593Smuzhiyun 	 * left this network namespace.  This is because
2719*4882a593Smuzhiyun 	 * unregister_netdevice_many and netdev_run_todo has completed
2720*4882a593Smuzhiyun 	 * for each network device that was in this network namespace.
2721*4882a593Smuzhiyun 	 *
2722*4882a593Smuzhiyun 	 * As such no additional rcu synchronization is necessary when
2723*4882a593Smuzhiyun 	 * freeing the platform_label table.
2724*4882a593Smuzhiyun 	 */
2725*4882a593Smuzhiyun 	rtnl_lock();
2726*4882a593Smuzhiyun 	platform_label = rtnl_dereference(net->mpls.platform_label);
2727*4882a593Smuzhiyun 	platform_labels = net->mpls.platform_labels;
2728*4882a593Smuzhiyun 	for (index = 0; index < platform_labels; index++) {
2729*4882a593Smuzhiyun 		struct mpls_route *rt = rtnl_dereference(platform_label[index]);
2730*4882a593Smuzhiyun 		RCU_INIT_POINTER(platform_label[index], NULL);
2731*4882a593Smuzhiyun 		mpls_notify_route(net, index, rt, NULL, NULL);
2732*4882a593Smuzhiyun 		mpls_rt_free(rt);
2733*4882a593Smuzhiyun 	}
2734*4882a593Smuzhiyun 	rtnl_unlock();
2735*4882a593Smuzhiyun 
2736*4882a593Smuzhiyun 	kvfree(platform_label);
2737*4882a593Smuzhiyun }
2738*4882a593Smuzhiyun 
2739*4882a593Smuzhiyun static struct pernet_operations mpls_net_ops = {
2740*4882a593Smuzhiyun 	.init = mpls_net_init,
2741*4882a593Smuzhiyun 	.exit = mpls_net_exit,
2742*4882a593Smuzhiyun };
2743*4882a593Smuzhiyun 
2744*4882a593Smuzhiyun static struct rtnl_af_ops mpls_af_ops __read_mostly = {
2745*4882a593Smuzhiyun 	.family		   = AF_MPLS,
2746*4882a593Smuzhiyun 	.fill_stats_af	   = mpls_fill_stats_af,
2747*4882a593Smuzhiyun 	.get_stats_af_size = mpls_get_stats_af_size,
2748*4882a593Smuzhiyun };
2749*4882a593Smuzhiyun 
mpls_init(void)2750*4882a593Smuzhiyun static int __init mpls_init(void)
2751*4882a593Smuzhiyun {
2752*4882a593Smuzhiyun 	int err;
2753*4882a593Smuzhiyun 
2754*4882a593Smuzhiyun 	BUILD_BUG_ON(sizeof(struct mpls_shim_hdr) != 4);
2755*4882a593Smuzhiyun 
2756*4882a593Smuzhiyun 	err = register_pernet_subsys(&mpls_net_ops);
2757*4882a593Smuzhiyun 	if (err)
2758*4882a593Smuzhiyun 		goto out;
2759*4882a593Smuzhiyun 
2760*4882a593Smuzhiyun 	err = register_netdevice_notifier(&mpls_dev_notifier);
2761*4882a593Smuzhiyun 	if (err)
2762*4882a593Smuzhiyun 		goto out_unregister_pernet;
2763*4882a593Smuzhiyun 
2764*4882a593Smuzhiyun 	dev_add_pack(&mpls_packet_type);
2765*4882a593Smuzhiyun 
2766*4882a593Smuzhiyun 	rtnl_af_register(&mpls_af_ops);
2767*4882a593Smuzhiyun 
2768*4882a593Smuzhiyun 	rtnl_register_module(THIS_MODULE, PF_MPLS, RTM_NEWROUTE,
2769*4882a593Smuzhiyun 			     mpls_rtm_newroute, NULL, 0);
2770*4882a593Smuzhiyun 	rtnl_register_module(THIS_MODULE, PF_MPLS, RTM_DELROUTE,
2771*4882a593Smuzhiyun 			     mpls_rtm_delroute, NULL, 0);
2772*4882a593Smuzhiyun 	rtnl_register_module(THIS_MODULE, PF_MPLS, RTM_GETROUTE,
2773*4882a593Smuzhiyun 			     mpls_getroute, mpls_dump_routes, 0);
2774*4882a593Smuzhiyun 	rtnl_register_module(THIS_MODULE, PF_MPLS, RTM_GETNETCONF,
2775*4882a593Smuzhiyun 			     mpls_netconf_get_devconf,
2776*4882a593Smuzhiyun 			     mpls_netconf_dump_devconf, 0);
2777*4882a593Smuzhiyun 	err = ipgre_tunnel_encap_add_mpls_ops();
2778*4882a593Smuzhiyun 	if (err)
2779*4882a593Smuzhiyun 		pr_err("Can't add mpls over gre tunnel ops\n");
2780*4882a593Smuzhiyun 
2781*4882a593Smuzhiyun 	err = 0;
2782*4882a593Smuzhiyun out:
2783*4882a593Smuzhiyun 	return err;
2784*4882a593Smuzhiyun 
2785*4882a593Smuzhiyun out_unregister_pernet:
2786*4882a593Smuzhiyun 	unregister_pernet_subsys(&mpls_net_ops);
2787*4882a593Smuzhiyun 	goto out;
2788*4882a593Smuzhiyun }
2789*4882a593Smuzhiyun module_init(mpls_init);
2790*4882a593Smuzhiyun 
mpls_exit(void)2791*4882a593Smuzhiyun static void __exit mpls_exit(void)
2792*4882a593Smuzhiyun {
2793*4882a593Smuzhiyun 	rtnl_unregister_all(PF_MPLS);
2794*4882a593Smuzhiyun 	rtnl_af_unregister(&mpls_af_ops);
2795*4882a593Smuzhiyun 	dev_remove_pack(&mpls_packet_type);
2796*4882a593Smuzhiyun 	unregister_netdevice_notifier(&mpls_dev_notifier);
2797*4882a593Smuzhiyun 	unregister_pernet_subsys(&mpls_net_ops);
2798*4882a593Smuzhiyun 	ipgre_tunnel_encap_del_mpls_ops();
2799*4882a593Smuzhiyun }
2800*4882a593Smuzhiyun module_exit(mpls_exit);
2801*4882a593Smuzhiyun 
2802*4882a593Smuzhiyun MODULE_DESCRIPTION("MultiProtocol Label Switching");
2803*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
2804*4882a593Smuzhiyun MODULE_ALIAS_NETPROTO(PF_MPLS);
2805