Hello,
On Mon, 28 Oct 2013, Daniel Borkmann wrote:
> Unlike UDP or TCP, we do not take the pseudo-header into
> account in SCTP checksums. So in case port mapping is the
> very same, we do not need to recalculate the whole SCTP
> checksum in software, which is very expensive.
>
> Also, similarly as in TCP, take into account when a private
> helper mangled the packet. In that case, we also need to
> recalculate the checksum even if ports might be same.
>
> Thanks for feedback regarding skb->ip_summed checks from
> Julian Anastasov; here's a discussion on these checks for
> snat and dnat:
>
> * For snat_handler(), we can see CHECKSUM_PARTIAL from
> virtual devices, and from LOCAL_OUT, otherwise it
> should be CHECKSUM_UNNECESSARY. In general, in snat it
> is more complex. skb contains the original route and
> ip_vs_route_me_harder() can change the route after
> snat_handler. So, for locally generated replies from
> local server we can not preserve the CHECKSUM_PARTIAL
> mode. It is an chicken or egg dilemma: snat_handler
> needs the device after rerouting (to check for
> NETIF_F_SCTP_CSUM), while ip_route_me_harder() wants
> the snat_handler() to put the new saddr for proper
> rerouting.
>
> * For dnat_handler(), we should not see CHECKSUM_COMPLETE
> for SCTP, in fact the small set of drivers that support
> SCTP offloading return CHECKSUM_UNNECESSARY on correctly
> received SCTP csum. We can see CHECKSUM_PARTIAL from
> local stack or received from virtual drivers. The idea is
> that SCTP decides to avoid csum calculation if hardware
> supports offloading. IPVS can change the device after
> rerouting to real server but we can preserve the
> CHECKSUM_PARTIAL mode if the new device supports
> offloading too. This works because skb dst is changed
> before dnat_handler and we see the new device. So, checks
> in the 'if' part will decide whether it is ok to keep
> CHECKSUM_PARTIAL for the output. If the packet was with
> CHECKSUM_NONE, hence we deal with unknown checksum. As we
> recalculate the sum for IP header in all cases, it should
> be safe to use CHECKSUM_UNNECESSARY. We can forward wrong
> checksum in this case (without cp->app). In case of
> CHECKSUM_UNNECESSARY, the csum was valid on receive.
>
> Signed-off-by: Daniel Borkmann <dborkman@xxxxxxxxxx>
Looks good, thanks!
Signed-off-by: Julian Anastasov <ja@xxxxxx>
> ---
> v1->v2: - Applied skb->ip_summed feedback from Julian, thanks!
> v2->v3: - Minor cosmetic change to fix checkpatch warning
>
> net/netfilter/ipvs/ip_vs_proto_sctp.c | 39
> +++++++++++++++++++++++++++++------
> 1 file changed, 33 insertions(+), 6 deletions(-)
>
> diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c
> b/net/netfilter/ipvs/ip_vs_proto_sctp.c
> index 9ca7aa0..2f7ea75 100644
> --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c
> +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c
> @@ -81,6 +81,7 @@ sctp_snat_handler(struct sk_buff *skb, struct
> ip_vs_protocol *pp,
> {
> sctp_sctphdr_t *sctph;
> unsigned int sctphoff = iph->len;
> + bool payload_csum = false;
>
> #ifdef CONFIG_IP_VS_IPV6
> if (cp->af == AF_INET6 && iph->fragoffs)
> @@ -92,19 +93,31 @@ sctp_snat_handler(struct sk_buff *skb, struct
> ip_vs_protocol *pp,
> return 0;
>
> if (unlikely(cp->app != NULL)) {
> + int ret;
> +
> /* Some checks before mangling */
> if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
> return 0;
>
> /* Call application helper if needed */
> - if (!ip_vs_app_pkt_out(cp, skb))
> + ret = ip_vs_app_pkt_out(cp, skb);
> + if (ret == 0)
> return 0;
> + /* ret=2: csum update is needed after payload mangling */
> + if (ret == 2)
> + payload_csum = true;
> }
>
> sctph = (void *) skb_network_header(skb) + sctphoff;
> - sctph->source = cp->vport;
>
> - sctp_nat_csum(skb, sctph, sctphoff);
> + /* Only update csum if we really have to */
> + if (sctph->source != cp->vport || payload_csum ||
> + skb->ip_summed == CHECKSUM_PARTIAL) {
> + sctph->source = cp->vport;
> + sctp_nat_csum(skb, sctph, sctphoff);
> + } else {
> + skb->ip_summed = CHECKSUM_UNNECESSARY;
> + }
>
> return 1;
> }
> @@ -115,6 +128,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct
> ip_vs_protocol *pp,
> {
> sctp_sctphdr_t *sctph;
> unsigned int sctphoff = iph->len;
> + bool payload_csum = false;
>
> #ifdef CONFIG_IP_VS_IPV6
> if (cp->af == AF_INET6 && iph->fragoffs)
> @@ -126,19 +140,32 @@ sctp_dnat_handler(struct sk_buff *skb, struct
> ip_vs_protocol *pp,
> return 0;
>
> if (unlikely(cp->app != NULL)) {
> + int ret;
> +
> /* Some checks before mangling */
> if (pp->csum_check && !pp->csum_check(cp->af, skb, pp))
> return 0;
>
> /* Call application helper if needed */
> - if (!ip_vs_app_pkt_in(cp, skb))
> + ret = ip_vs_app_pkt_in(cp, skb);
> + if (ret == 0)
> return 0;
> + /* ret=2: csum update is needed after payload mangling */
> + if (ret == 2)
> + payload_csum = true;
> }
>
> sctph = (void *) skb_network_header(skb) + sctphoff;
> - sctph->dest = cp->dport;
>
> - sctp_nat_csum(skb, sctph, sctphoff);
> + /* Only update csum if we really have to */
> + if (sctph->dest != cp->dport || payload_csum ||
> + (skb->ip_summed == CHECKSUM_PARTIAL &&
> + !(skb_dst(skb)->dev->features & NETIF_F_SCTP_CSUM))) {
> + sctph->dest = cp->dport;
> + sctp_nat_csum(skb, sctph, sctphoff);
> + } else if (skb->ip_summed != CHECKSUM_PARTIAL) {
> + skb->ip_summed = CHECKSUM_UNNECESSARY;
> + }
>
> return 1;
> }
> --
> 1.7.11.7
Regards
--
Julian Anastasov <ja@xxxxxx>
--
To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
|