Commit b2e653bc authored by Petr Machata's avatar Petr Machata Committed by Jakub Kicinski
Browse files

net: ipv4: ipmr: Split ipmr_queue_xmit() in two



Some of the work of ipmr_queue_xmit() is specific to IPMR forwarding, and
should not take place on the output path. In order to allow reuse of the
common parts, split the function into two: the ipmr_prepare_xmit() helper
that takes care of the common bits, and the ipmr_queue_fwd_xmit(), which
invokes the former and encapsulates the whole forwarding algorithm.

Signed-off-by: default avatarPetr Machata <petrm@nvidia.com>
Reviewed-by: default avatarIdo Schimmel <idosch@nvidia.com>
Reviewed-by: default avatarNikolay Aleksandrov <razor@blackwall.org>
Link: https://patch.msgid.link/4e8db165572a4f8bd29a723a801e854e9d20df4d.1750113335.git.petrm@nvidia.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 3b7bc938
Loading
Loading
Loading
Loading
+29 −16
Original line number Diff line number Diff line
@@ -1853,8 +1853,8 @@ static bool ipmr_forward_offloaded(struct sk_buff *skb, struct mr_table *mrt,

/* Processing handlers for ipmr_forward, under rcu_read_lock() */

static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
			    int in_vifi, struct sk_buff *skb, int vifi)
static int ipmr_prepare_xmit(struct net *net, struct mr_table *mrt,
			     struct sk_buff *skb, int vifi)
{
	const struct iphdr *iph = ip_hdr(skb);
	struct vif_device *vif = &mrt->vif_table[vifi];
@@ -1865,7 +1865,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,

	vif_dev = vif_dev_read(vif);
	if (!vif_dev)
		goto out_free;
		return -1;

	if (vif->flags & VIFF_REGISTER) {
		WRITE_ONCE(vif->pkt_out, vif->pkt_out + 1);
@@ -1873,12 +1873,9 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
		DEV_STATS_ADD(vif_dev, tx_bytes, skb->len);
		DEV_STATS_INC(vif_dev, tx_packets);
		ipmr_cache_report(mrt, skb, vifi, IGMPMSG_WHOLEPKT);
		goto out_free;
		return -1;
	}

	if (ipmr_forward_offloaded(skb, mrt, in_vifi, vifi))
		goto out_free;

	if (vif->flags & VIFF_TUNNEL) {
		rt = ip_route_output_ports(net, &fl4, NULL,
					   vif->remote, vif->local,
@@ -1886,7 +1883,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
					   IPPROTO_IPIP,
					   iph->tos & INET_DSCP_MASK, vif->link);
		if (IS_ERR(rt))
			goto out_free;
			return -1;
		encap = sizeof(struct iphdr);
	} else {
		rt = ip_route_output_ports(net, &fl4, NULL, iph->daddr, 0,
@@ -1894,7 +1891,7 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
					   IPPROTO_IPIP,
					   iph->tos & INET_DSCP_MASK, vif->link);
		if (IS_ERR(rt))
			goto out_free;
			return -1;
	}

	if (skb->len+encap > dst_mtu(&rt->dst) && (ntohs(iph->frag_off) & IP_DF)) {
@@ -1904,14 +1901,14 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
		 */
		IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
		ip_rt_put(rt);
		goto out_free;
		return -1;
	}

	encap += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len;

	if (skb_cow(skb, encap)) {
		ip_rt_put(rt);
		goto out_free;
		return -1;
	}

	WRITE_ONCE(vif->pkt_out, vif->pkt_out + 1);
@@ -1931,6 +1928,22 @@ static void ipmr_queue_xmit(struct net *net, struct mr_table *mrt,
		DEV_STATS_ADD(vif_dev, tx_bytes, skb->len);
	}

	return 0;
}

static void ipmr_queue_fwd_xmit(struct net *net, struct mr_table *mrt,
				int in_vifi, struct sk_buff *skb, int vifi)
{
	struct rtable *rt;

	if (ipmr_forward_offloaded(skb, mrt, in_vifi, vifi))
		goto out_free;

	if (ipmr_prepare_xmit(net, mrt, skb, vifi))
		goto out_free;

	rt = skb_rtable(skb);

	IPCB(skb)->flags |= IPSKB_FORWARDED;

	/* RFC1584 teaches, that DVMRP/PIM router must deliver packets locally
@@ -2062,7 +2075,7 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt,
				struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);

				if (skb2)
					ipmr_queue_xmit(net, mrt, true_vifi,
					ipmr_queue_fwd_xmit(net, mrt, true_vifi,
							    skb2, psend);
			}
			psend = ct;
@@ -2074,10 +2087,10 @@ static void ip_mr_forward(struct net *net, struct mr_table *mrt,
			struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);

			if (skb2)
				ipmr_queue_xmit(net, mrt, true_vifi, skb2,
				ipmr_queue_fwd_xmit(net, mrt, true_vifi, skb2,
						    psend);
		} else {
			ipmr_queue_xmit(net, mrt, true_vifi, skb, psend);
			ipmr_queue_fwd_xmit(net, mrt, true_vifi, skb, psend);
			return;
		}
	}