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:
parent
80661e7687
commit
84287bb328
|
@ -41,6 +41,7 @@ enum {
|
|||
ILA_CSUM_ADJUST_TRANSPORT,
|
||||
ILA_CSUM_NEUTRAL_MAP,
|
||||
ILA_CSUM_NO_ACTION,
|
||||
ILA_CSUM_NEUTRAL_MAP_AUTO,
|
||||
};
|
||||
|
||||
#endif /* _UAPI_LINUX_ILA_H */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -127,6 +127,7 @@ static int ila_build_state(struct nlattr *nla,
|
|||
struct lwtunnel_state *newts;
|
||||
const struct fib6_config *cfg6 = cfg;
|
||||
struct ila_addr *iaddr;
|
||||
u8 csum_mode = ILA_CSUM_NO_ACTION;
|
||||
int ret;
|
||||
|
||||
if (family != AF_INET6)
|
||||
|
@ -139,15 +140,6 @@ static int ila_build_state(struct nlattr *nla,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
iaddr = (struct ila_addr *)&cfg6->fc_dst;
|
||||
|
||||
if (!ila_addr_is_ila(iaddr) || ila_csum_neutral_set(iaddr->ident)) {
|
||||
/* Don't allow translation for a non-ILA address or checksum
|
||||
* neutral flag to be set.
|
||||
*/
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -155,6 +147,19 @@ static int ila_build_state(struct nlattr *nla,
|
|||
if (!tb[ILA_ATTR_LOCATOR])
|
||||
return -EINVAL;
|
||||
|
||||
iaddr = (struct ila_addr *)&cfg6->fc_dst;
|
||||
|
||||
if (tb[ILA_ATTR_CSUM_MODE])
|
||||
csum_mode = nla_get_u8(tb[ILA_ATTR_CSUM_MODE]);
|
||||
|
||||
if (csum_mode == ILA_CSUM_NEUTRAL_MAP &&
|
||||
ila_csum_neutral_set(iaddr->ident)) {
|
||||
/* Don't allow translation if checksum neutral bit is
|
||||
* configured and it's set in the SIR address.
|
||||
*/
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
newts = lwtunnel_state_alloc(sizeof(*ilwt));
|
||||
if (!newts)
|
||||
return -ENOMEM;
|
||||
|
@ -168,17 +173,13 @@ static int ila_build_state(struct nlattr *nla,
|
|||
|
||||
p = ila_params_lwtunnel(newts);
|
||||
|
||||
p->csum_mode = csum_mode;
|
||||
p->locator.v64 = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]);
|
||||
|
||||
/* Precompute checksum difference for translation since we
|
||||
* know both the old locator and the new one.
|
||||
*/
|
||||
p->locator_match = iaddr->loc;
|
||||
p->csum_diff = compute_csum_diff8(
|
||||
(__be32 *)&p->locator_match, (__be32 *)&p->locator);
|
||||
|
||||
if (tb[ILA_ATTR_CSUM_MODE])
|
||||
p->csum_mode = nla_get_u8(tb[ILA_ATTR_CSUM_MODE]);
|
||||
|
||||
ila_init_saved_csum(p);
|
||||
|
||||
|
|
|
@ -138,6 +138,8 @@ static int parse_nl_config(struct genl_info *info,
|
|||
|
||||
if (info->attrs[ILA_ATTR_CSUM_MODE])
|
||||
xp->ip.csum_mode = nla_get_u8(info->attrs[ILA_ATTR_CSUM_MODE]);
|
||||
else
|
||||
xp->ip.csum_mode = ILA_CSUM_NO_ACTION;
|
||||
|
||||
if (info->attrs[ILA_ATTR_IFINDEX])
|
||||
xp->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]);
|
||||
|
@ -198,7 +200,7 @@ static void ila_free_cb(void *ptr, void *arg)
|
|||
}
|
||||
}
|
||||
|
||||
static int ila_xlat_addr(struct sk_buff *skb, bool set_csum_neutral);
|
||||
static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila);
|
||||
|
||||
static unsigned int
|
||||
ila_nf_input(void *priv,
|
||||
|
@ -396,7 +398,7 @@ static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg)
|
|||
(__force u64)ila->xp.ip.locator_match.v64,
|
||||
ILA_ATTR_PAD) ||
|
||||
nla_put_s32(msg, ILA_ATTR_IFINDEX, ila->xp.ifindex) ||
|
||||
nla_put_u32(msg, ILA_ATTR_CSUM_MODE, ila->xp.ip.csum_mode))
|
||||
nla_put_u8(msg, ILA_ATTR_CSUM_MODE, ila->xp.ip.csum_mode))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
|
@ -607,7 +609,7 @@ static struct pernet_operations ila_net_ops = {
|
|||
.size = sizeof(struct ila_net),
|
||||
};
|
||||
|
||||
static int ila_xlat_addr(struct sk_buff *skb, bool set_csum_neutral)
|
||||
static int ila_xlat_addr(struct sk_buff *skb, bool sir2ila)
|
||||
{
|
||||
struct ila_map *ila;
|
||||
struct ipv6hdr *ip6h = ipv6_hdr(skb);
|
||||
|
@ -626,7 +628,7 @@ static int ila_xlat_addr(struct sk_buff *skb, bool set_csum_neutral)
|
|||
|
||||
ila = ila_lookup_wildcards(iaddr, skb->dev->ifindex, ilan);
|
||||
if (ila)
|
||||
ila_update_ipv6_locator(skb, &ila->xp.ip, set_csum_neutral);
|
||||
ila_update_ipv6_locator(skb, &ila->xp.ip, sir2ila);
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
|
|
Loading…
Reference in New Issue