ila: add checksum neutral map auto

Add checksum neutral auto that performs checksum neutral mapping
without using the C-bit. This is enabled by configuration of
a mapping.

The checksum neutral function has been split into
ila_csum_do_neutral_fmt and ila_csum_do_neutral_nofmt. The former
handles the C-bit and includes it in the adjustment value. The latter
just sets the adjustment value on the locator diff only.

Added configuration for checksum neutral map aut in ila_lwt
and ila_xlat.

Signed-off-by: Tom Herbert <tom@quantonium.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Tom Herbert
2017-11-05 15:58:23 -08:00
committed by David S. Miller
parent 80661e7687
commit 84287bb328
4 changed files with 61 additions and 44 deletions

View File

@@ -37,8 +37,8 @@ static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p)
return get_csum_diff_iaddr(ila_a2i(&ip6h->daddr), p);
}
static void ila_csum_do_neutral(struct ila_addr *iaddr,
struct ila_params *p)
static void ila_csum_do_neutral_fmt(struct ila_addr *iaddr,
struct ila_params *p)
{
__sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3];
__wsum diff, fval;
@@ -60,13 +60,23 @@ static void ila_csum_do_neutral(struct ila_addr *iaddr,
iaddr->ident.csum_neutral ^= 1;
}
static void ila_csum_do_neutral_nofmt(struct ila_addr *iaddr,
struct ila_params *p)
{
__sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3];
__wsum diff;
diff = get_csum_diff_iaddr(iaddr, p);
*adjust = ~csum_fold(csum_add(diff, csum_unfold(*adjust)));
}
static void ila_csum_adjust_transport(struct sk_buff *skb,
struct ila_params *p)
{
__wsum diff;
struct ipv6hdr *ip6h = ipv6_hdr(skb);
struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
size_t nhoff = sizeof(struct ipv6hdr);
struct ipv6hdr *ip6h = ipv6_hdr(skb);
__wsum diff;
switch (ip6h->nexthdr) {
case NEXTHDR_TCP:
@@ -105,36 +115,39 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
}
break;
}
/* Now change destination address */
iaddr->loc = p->locator;
}
void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p,
bool set_csum_neutral)
bool sir2ila)
{
struct ipv6hdr *ip6h = ipv6_hdr(skb);
struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
/* First deal with the transport checksum */
if (ila_csum_neutral_set(iaddr->ident)) {
/* C-bit is set in the locator indicating that this
* is a locator being translated to a SIR address.
* Perform (receiver) checksum-neutral translation.
*/
if (!set_csum_neutral)
ila_csum_do_neutral(iaddr, p);
} else {
switch (p->csum_mode) {
case ILA_CSUM_ADJUST_TRANSPORT:
ila_csum_adjust_transport(skb, p);
break;
case ILA_CSUM_NEUTRAL_MAP:
ila_csum_do_neutral(iaddr, p);
break;
case ILA_CSUM_NO_ACTION:
switch (p->csum_mode) {
case ILA_CSUM_ADJUST_TRANSPORT:
ila_csum_adjust_transport(skb, p);
break;
case ILA_CSUM_NEUTRAL_MAP:
if (sir2ila) {
if (WARN_ON(ila_csum_neutral_set(iaddr->ident))) {
/* Checksum flag should never be
* set in a formatted SIR address.
*/
break;
}
} else if (!ila_csum_neutral_set(iaddr->ident)) {
/* ILA to SIR translation and C-bit isn't
* set so we're good.
*/
break;
}
ila_csum_do_neutral_fmt(iaddr, p);
break;
case ILA_CSUM_NEUTRAL_MAP_AUTO:
ila_csum_do_neutral_nofmt(iaddr, p);
break;
case ILA_CSUM_NO_ACTION:
break;
}
/* Now change destination address */