static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
			struct packet_type *pt, struct net_device *orig_dev)
{
	struct net *net = dev_net(dev);
	struct mpls_shim_hdr *hdr;
	struct mpls_route *rt;
	struct mpls_nh *nh;
	struct mpls_entry_decoded dec;
	struct net_device *out_dev;
	struct mpls_dev *out_mdev;
	struct mpls_dev *mdev;
	unsigned int hh_len;
	unsigned int new_header_size;
	unsigned int mtu;
	int err;

	/* Careful this entire function runs inside of an rcu critical section */

	mdev = mpls_dev_get(dev);
	if (!mdev)
		goto drop;

	MPLS_INC_STATS_LEN(mdev, skb->len, rx_packets,
			   rx_bytes);

	if (!mdev->input_enabled) {
		MPLS_INC_STATS(mdev, rx_dropped);
		goto drop;
	}

	if (skb->pkt_type != PACKET_HOST)
		goto err;

	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
		goto err;

	if (!pskb_may_pull(skb, sizeof(*hdr)))
		goto err;

	/* Read and decode the label */
	hdr = mpls_hdr(skb);
	dec = mpls_entry_decode(hdr);

	rt = mpls_route_input_rcu(net, dec.label);
	if (!rt) {
		MPLS_INC_STATS(mdev, rx_noroute);
		goto drop;
	}

	nh = mpls_select_multipath(rt, skb);
	if (!nh)
		goto err;

	/* Pop the label */
	skb_pull(skb, sizeof(*hdr));
	skb_reset_network_header(skb);

	skb_orphan(skb);

	if (skb_warn_if_lro(skb))
		goto err;

	skb_forward_csum(skb);

	/* Verify ttl is valid */
	if (dec.ttl <= 1)
		goto err;
	dec.ttl -= 1;

	/* Find the output device */
	out_dev = rcu_dereference(nh->nh_dev);
	if (!mpls_output_possible(out_dev))
		goto tx_err;

	/* Verify the destination can hold the packet */
	new_header_size = mpls_nh_header_size(nh);
	mtu = mpls_dev_mtu(out_dev);
	if (mpls_pkt_too_big(skb, mtu - new_header_size))
		goto tx_err;

	hh_len = LL_RESERVED_SPACE(out_dev);
	if (!out_dev->header_ops)
		hh_len = 0;

	/* Ensure there is enough space for the headers in the skb */
	if (skb_cow(skb, hh_len + new_header_size))
		goto tx_err;

	skb->dev = out_dev;
	skb->protocol = htons(ETH_P_MPLS_UC);

	if (unlikely(!new_header_size && dec.bos)) {
		/* Penultimate hop popping */
		if (!mpls_egress(dev_net(out_dev), rt, skb, dec))
			goto err;
	} else {
		bool bos;
		int i;
		skb_push(skb, new_header_size);
		skb_reset_network_header(skb);
		/* Push the new labels */
		hdr = mpls_hdr(skb);
		bos = dec.bos;
		for (i = nh->nh_labels - 1; i >= 0; i--) {
			hdr[i] = mpls_entry_encode(nh->nh_label[i],
						   dec.ttl, 0, bos);
			bos = false;
		}
	}

	mpls_stats_inc_outucastpkts(out_dev, skb);

	/* If via wasn't specified then send out using device address */
	if (nh->nh_via_table == MPLS_NEIGH_TABLE_UNSPEC)
		err = neigh_xmit(NEIGH_LINK_TABLE, out_dev,
				 out_dev->dev_addr, skb);
	else
		err = neigh_xmit(nh->nh_via_table, out_dev,
				 mpls_nh_via(rt, nh), skb);
	if (err)
		net_dbg_ratelimited("%s: packet transmission failed: %d\n",
				    __func__, err);
	return 0;

tx_err:
	out_mdev = out_dev ? mpls_dev_get(out_dev) : NULL;
	if (out_mdev)
		MPLS_INC_STATS(out_mdev, tx_errors);
	goto drop;
err:
	MPLS_INC_STATS(mdev, rx_errors);
drop:
	kfree_skb(skb);
	return NET_RX_DROP;
}
static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
			struct packet_type *pt, struct net_device *orig_dev)
{
	struct net *net = dev_net(dev);
	struct mpls_shim_hdr *hdr;
	struct mpls_route *rt;
	struct mpls_nh *nh;
	struct mpls_entry_decoded dec;
	struct net_device *out_dev;
	struct mpls_dev *out_mdev;
	struct mpls_dev *mdev;
	unsigned int hh_len;
	unsigned int new_header_size;
	unsigned int mtu;
	int err;

	 

	mdev = mpls_dev_get(dev);
	if (!mdev)
		goto drop;

	MPLS_INC_STATS_LEN(mdev, skb->len, rx_packets,
			   rx_bytes);

	if (!mdev->input_enabled) {
		MPLS_INC_STATS(mdev, rx_dropped);
		goto drop;
	}

	if (skb->pkt_type != PACKET_HOST)
		goto err;

	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
		goto err;

	if (!pskb_may_pull(skb, sizeof(*hdr)))
		goto err;

	 
	hdr = mpls_hdr(skb);
	dec = mpls_entry_decode(hdr);

	rt = mpls_route_input_rcu(net, dec.label);
	if (!rt) {
		MPLS_INC_STATS(mdev, rx_noroute);
		goto drop;
	}

	nh = mpls_select_multipath(rt, skb);
	if (!nh)
		goto err;

	 
	skb_pull(skb, sizeof(*hdr));
	skb_reset_network_header(skb);

	skb_orphan(skb);

	if (skb_warn_if_lro(skb))
		goto err;

	skb_forward_csum(skb);

	 
	if (dec.ttl <= 1)
		goto err;
	dec.ttl -= 1;

	 
	out_dev = rcu_dereference(nh->nh_dev);
	if (!mpls_output_possible(out_dev))
		goto tx_err;

	 
	new_header_size = mpls_nh_header_size(nh);
	mtu = mpls_dev_mtu(out_dev);
	if (mpls_pkt_too_big(skb, mtu - new_header_size))
		goto tx_err;

	hh_len = LL_RESERVED_SPACE(out_dev);
	if (!out_dev->header_ops)
		hh_len = 0;

	 
	if (skb_cow(skb, hh_len + new_header_size))
		goto tx_err;

	skb->dev = out_dev;
	skb->protocol = htons(ETH_P_MPLS_UC);

	if (unlikely(!new_header_size && dec.bos)) {
		 
		if (!mpls_egress(dev_net(out_dev), rt, skb, dec))
			goto err;
	} else {
		bool bos;
		int i;
		skb_push(skb, new_header_size);
		skb_reset_network_header(skb);
		 
		hdr = mpls_hdr(skb);
		bos = dec.bos;
		for (i = nh->nh_labels - 1; i >= 0; i--) {
			hdr[i] = mpls_entry_encode(nh->nh_label[i],
						   dec.ttl, 0, bos);
			bos = false;
		}
	}

	mpls_stats_inc_outucastpkts(out_dev, skb);

	 
	if (nh->nh_via_table == MPLS_NEIGH_TABLE_UNSPEC)
		err = neigh_xmit(NEIGH_LINK_TABLE, out_dev,
				 out_dev->dev_addr, skb);
	else
		err = neigh_xmit(nh->nh_via_table, out_dev,
				 mpls_nh_via(rt, nh), skb);
	if (err)
		net_dbg_ratelimited("%s: packet transmission failed: %d\n",
				    __func__, err);
	return 0;

tx_err:
	out_mdev = out_dev ? mpls_dev_get(out_dev) : NULL;
	if (out_mdev)
		MPLS_INC_STATS(out_mdev, tx_errors);
	goto drop;
err:
	MPLS_INC_STATS(mdev, rx_errors);
drop:
	kfree_skb(skb);
	return NET_RX_DROP;
}