Commit 8bd1ee2e authored by David S. Miller's avatar David S. Miller

Merge branch 'ila-make-identifier-format-optional-and-other-fixes'

Tom Herbert says:

====================
ila: make identifier format optional and other fixes

The identifier type and checksum neutral mapping bits are optional
in identifier formats. This patch set fixes the implementation to
make them optional and configurable.

Specific items:

  - Clean up checksum diff code in ILA
  - Add checksum neutral mapping auto so that checksum neutral
    mapping can be configured without requiring use of the C-bit
  - Add identifier type configuration and allow identifier
    type to be configured so that the identifier type field does
    not need to be present
  - Added ILA documention: ila.txt

I have fixes for ILA in iproute2 that will be poseted separately.

Tested: Ran netperf TCP_RR on various combinations of checksum
mode and the two supported identifier types.

v2:
  - Add proper sign off
  - In ILA LWT, only check prefix length includes identifier type
    if identifier type is enabled (ILA_ATYPE_USE_FORMAT).
  - Add a hook type so that it can be specified whether ILA
    translation is done on input or output route funciton in
    LWT.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3e29cd0e 7afc19bc
Identifier Locator Addressing (ILA)
Introduction
============
Identifier-locator addressing (ILA) is a technique used with IPv6 that
differentiates between location and identity of a network node. Part of an
address expresses the immutable identity of the node, and another part
indicates the location of the node which can be dynamic. Identifier-locator
addressing can be used to efficiently implement overlay networks for
network virtualization as well as solutions for use cases in mobility.
ILA can be thought of as means to implement an overlay network without
encapsulation. This is accomplished by performing network address
translation on destination addresses as a packet traverses a network. To
the network, an ILA translated packet appears to be no different than any
other IPv6 packet. For instance, if the transport protocol is TCP then an
ILA translated packet looks like just another TCP/IPv6 packet. The
advantage of this is that ILA is transparent to the network so that
optimizations in the network, such as ECMP, RSS, GRO, GSO, etc., just work.
The ILA protocol is described in Internet-Draft draft-herbert-intarea-ila.
ILA terminology
===============
- Identifier A number that identifies an addressable node in the network
independent of its location. ILA identifiers are sixty-four
bit values.
- Locator A network prefix that routes to a physical host. Locators
provide the topological location of an addressed node. ILA
locators are sixty-four bit prefixes.
- ILA mapping
A mapping of an ILA identifier to a locator (or to a
locator and meta data). An ILA domain maintains a database
that contains mappings for all destinations in the domain.
- SIR address
An IPv6 address composed of a SIR prefix (upper sixty-
four bits) and an identifier (lower sixty-four bits).
SIR addresses are visible to applications and provide a
means for them to address nodes independent of their
location.
- ILA address
An IPv6 address composed of a locator (upper sixty-four
bits) and an identifier (low order sixty-four bits). ILA
addresses are never visible to an application.
- ILA host An end host that is capable of performing ILA translations
on transmit or receive.
- ILA router A network node that performs ILA translation and forwarding
of translated packets.
- ILA forwarding cache
A type of ILA router that only maintains a working set
cache of mappings.
- ILA node A network node capable of performing ILA translations. This
can be an ILA router, ILA forwarding cache, or ILA host.
Operation
=========
There are two fundamental operations with ILA:
- Translate a SIR address to an ILA address. This is performed on ingress
to an ILA overlay.
- Translate an ILA address to a SIR address. This is performed on egress
from the ILA overlay.
ILA can be deployed either on end hosts or intermediate devices in the
network; these are provided by "ILA hosts" and "ILA routers" respectively.
Configuration and datapath for these two points of deployment is somewhat
different.
The diagram below illustrates the flow of packets through ILA as well
as showing ILA hosts and routers.
+--------+ +--------+
| Host A +-+ +--->| Host B |
| | | (2) ILA (') | |
+--------+ | ...addressed.... ( ) +--------+
V +---+--+ . packet . +---+--+ (_)
(1) SIR | | ILA |----->-------->---->| ILA | | (3) SIR
addressed +->|router| . . |router|->-+ addressed
packet +---+--+ . IPv6 . +---+--+ packet
/ . Network .
/ . . +--+-++--------+
+--------+ / . . |ILA || Host |
| Host +--+ . .- -|host|| |
| | . . +--+-++--------+
+--------+ ................
Transport checksum handling
===========================
When an address is translated by ILA, an encapsulated transport checksum
that includes the translated address in a pseudo header may be rendered
incorrect on the wire. This is a problem for intermediate devices,
including checksum offload in NICs, that process the checksum. There are
three options to deal with this:
- no action Allow the checksum to be incorrect on the wire. Before
a receiver verifies a checksum the ILA to SIR address
translation must be done.
- adjust transport checksum
When ILA translation is performed the packet is parsed
and if a transport layer checksum is found then it is
adjusted to reflect the correct checksum per the
translated address.
- checksum neutral mapping
When an address is translated the difference can be offset
elsewhere in a part of the packet that is covered by the
the checksum. The low order sixteen bits of the identifier
are used. This method is preferred since it doesn't require
parsing a packet beyond the IP header and in most cases the
adjustment can be precomputed and saved with the mapping.
Note that the checksum neutral adjustment affects the low order sixteen
bits of the identifier. When ILA to SIR address translation is done on
egress the low order bits are restored to the original value which
restores the identifier as it was originally sent.
Identifier types
================
ILA defines different types of identifiers for different use cases.
The defined types are:
0: interface identifier
1: locally unique identifier
2: virtual networking identifier for IPv4 address
3: virtual networking identifier for IPv6 unicast address
4: virtual networking identifier for IPv6 multicast address
5: non-local address identifier
In the current implementation of kernel ILA only locally unique identifiers
(LUID) are supported. LUID allows for a generic, unformatted 64 bit
identifier.
Identifier formats
==================
Kernel ILA supports two optional fields in an identifier for formatting:
"C-bit" and "identifier type". The presence of these fields is determined
by configuration as demonstrated below.
If the identifier type is present it occupies the three highest order
bits of an identifier. The possible values are given in the above list.
If the C-bit is present, this is used as an indication that checksum
neutral mapping has been done. The C-bit can only be set in an
ILA address, never a SIR address.
In the simplest format the identifier types, C-bit, and checksum
adjustment value are not present so an identifier is considered an
unstructured sixty-four bit value.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier |
+ +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The checksum neutral adjustment may be configured to always be
present using neutral-map-auto. In this case there is no C-bit, but the
checksum adjustment is in the low order 16 bits. The identifier is
still sixty-four bits.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identifier |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | Checksum-neutral adjustment |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The C-bit may used to explicitly indicate that checksum neutral
mapping has been applied to an ILA address. The format is:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |C| Identifier |
| +-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | Checksum-neutral adjustment |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
The identifier type field may be present to indicate the identifier
type. If it is not present then the type is inferred based on mapping
configuration. The checksum neutral adjustment may automatically
used with the identifier type as illustrated below.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type| Identifier |
+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | Checksum-neutral adjustment |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
If the identifier type and the C-bit can be present simultaneously so
the identifier format would be:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Type|C| Identifier |
+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | Checksum-neutral adjustment |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Configuration
=============
There are two methods to configure ILA mappings. One is by using LWT routes
and the other is ila_xlat (called from NFHOOK PREROUTING hook). ila_xlat
is intended to be used in the receive path for ILA hosts .
An ILA router has also been implemented in XDP. Description of that is
outside the scope of this document.
The usage of for ILA LWT routes is:
ip route add DEST/128 encap ila LOC csum-mode MODE ident-type TYPE via ADDR
Destination (DEST) can either be a SIR address (for an ILA host or ingress
ILA router) or an ILA address (egress ILA router). LOC is the sixty-four
bit locator (with format W:X:Y:Z) that overwrites the upper sixty-four
bits of the destination address. Checksum MODE is one of "no-action",
"adj-transport", "neutral-map", and "neutral-map-auto". If neutral-map is
set then the C-bit will be present. Identifier TYPE one of "luid" or
"use-format." In the case of use-format, the identifier type field is
present and the effective type is taken from that.
The usage of ila_xlat is:
ip ila add loc_match MATCH loc LOC csum-mode MODE ident-type TYPE
MATCH indicates the incoming locator that must be matched to apply
a the translaiton. LOC is the locator that overwrites the upper
sixty-four bits of the destination address. MODE and TYPE have the
same meanings as described above.
Some examples
=============
# Configure an ILA route that uses checksum neutral mapping as well
# as type field. Note that the type field is set in the SIR address
# (the 2000 implies type is 1 which is LUID).
ip route add 3333:0:0:1:2000:0:1:87/128 encap ila 2001:0:87:0 \
csum-mode neutral-map ident-type use-format
# Configure an ILA LWT route that uses auto checksum neutral mapping
# (no C-bit) and configure identifier type to be LUID so that the
# identifier type field will not be present.
ip route add 3333:0:0:1:2000:0:2:87/128 encap ila 2001:0:87:1 \
csum-mode neutral-map-auto ident-type luid
ila_xlat configuration
# Configure an ILA to SIR mapping that matches a locator and overwrites
# it with a SIR address (3333:0:0:1 in this example). The C-bit and
# identifier field are used.
ip ila add loc_match 2001:0:119:0 loc 3333:0:0:1 \
csum-mode neutral-map-auto ident-type use-format
# Configure an ILA to SIR mapping where checksum neutral is automatically
# set without the C-bit and the identifier type is configured to be LUID
# so that the identifier type field is not present.
ip ila add loc_match 2001:0:119:0 loc 3333:0:0:1 \
csum-mode neutral-map-auto ident-type use-format
...@@ -17,6 +17,8 @@ enum { ...@@ -17,6 +17,8 @@ enum {
ILA_ATTR_DIR, /* u32 */ ILA_ATTR_DIR, /* u32 */
ILA_ATTR_PAD, ILA_ATTR_PAD,
ILA_ATTR_CSUM_MODE, /* u8 */ ILA_ATTR_CSUM_MODE, /* u8 */
ILA_ATTR_IDENT_TYPE, /* u8 */
ILA_ATTR_HOOK_TYPE, /* u8 */
__ILA_ATTR_MAX, __ILA_ATTR_MAX,
}; };
...@@ -41,6 +43,25 @@ enum { ...@@ -41,6 +43,25 @@ enum {
ILA_CSUM_ADJUST_TRANSPORT, ILA_CSUM_ADJUST_TRANSPORT,
ILA_CSUM_NEUTRAL_MAP, ILA_CSUM_NEUTRAL_MAP,
ILA_CSUM_NO_ACTION, ILA_CSUM_NO_ACTION,
ILA_CSUM_NEUTRAL_MAP_AUTO,
};
enum {
ILA_ATYPE_IID = 0,
ILA_ATYPE_LUID,
ILA_ATYPE_VIRT_V4,
ILA_ATYPE_VIRT_UNI_V6,
ILA_ATYPE_VIRT_MULTI_V6,
ILA_ATYPE_NONLOCAL_ADDR,
ILA_ATYPE_RSVD_1,
ILA_ATYPE_RSVD_2,
ILA_ATYPE_USE_FORMAT = 32, /* Get type from type field in identifier */
};
enum {
ILA_HOOK_ROUTE_OUTPUT,
ILA_HOOK_ROUTE_INPUT,
}; };
#endif /* _UAPI_LINUX_ILA_H */ #endif /* _UAPI_LINUX_ILA_H */
...@@ -55,17 +55,6 @@ struct ila_identifier { ...@@ -55,17 +55,6 @@ struct ila_identifier {
}; };
}; };
enum {
ILA_ATYPE_IID = 0,
ILA_ATYPE_LUID,
ILA_ATYPE_VIRT_V4,
ILA_ATYPE_VIRT_UNI_V6,
ILA_ATYPE_VIRT_MULTI_V6,
ILA_ATYPE_RSVD_1,
ILA_ATYPE_RSVD_2,
ILA_ATYPE_RSVD_3,
};
#define CSUM_NEUTRAL_FLAG htonl(0x10000000) #define CSUM_NEUTRAL_FLAG htonl(0x10000000)
struct ila_addr { struct ila_addr {
...@@ -93,6 +82,7 @@ struct ila_params { ...@@ -93,6 +82,7 @@ struct ila_params {
struct ila_locator locator_match; struct ila_locator locator_match;
__wsum csum_diff; __wsum csum_diff;
u8 csum_mode; u8 csum_mode;
u8 ident_type;
}; };
static inline __wsum compute_csum_diff8(const __be32 *from, const __be32 *to) static inline __wsum compute_csum_diff8(const __be32 *from, const __be32 *to)
......
...@@ -13,30 +13,37 @@ ...@@ -13,30 +13,37 @@
#include <uapi/linux/ila.h> #include <uapi/linux/ila.h>
#include "ila.h" #include "ila.h"
static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p) void ila_init_saved_csum(struct ila_params *p)
{ {
struct ila_addr *iaddr = ila_a2i(&ip6h->daddr); if (!p->locator_match.v64)
return;
p->csum_diff = compute_csum_diff8(
(__be32 *)&p->locator,
(__be32 *)&p->locator_match);
}
static __wsum get_csum_diff_iaddr(struct ila_addr *iaddr, struct ila_params *p)
{
if (p->locator_match.v64) if (p->locator_match.v64)
return p->csum_diff; return p->csum_diff;
else else
return compute_csum_diff8((__be32 *)&iaddr->loc, return compute_csum_diff8((__be32 *)&p->locator,
(__be32 *)&p->locator); (__be32 *)&iaddr->loc);
}
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, static void ila_csum_do_neutral_fmt(struct ila_addr *iaddr,
struct ila_params *p) struct ila_params *p)
{ {
__sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3]; __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3];
__wsum diff, fval; __wsum diff, fval;
/* Check if checksum adjust value has been cached */ diff = get_csum_diff_iaddr(iaddr, p);
if (p->locator_match.v64) {
diff = p->csum_diff;
} else {
diff = compute_csum_diff8((__be32 *)&p->locator,
(__be32 *)iaddr);
}
fval = (__force __wsum)(ila_csum_neutral_set(iaddr->ident) ? fval = (__force __wsum)(ila_csum_neutral_set(iaddr->ident) ?
CSUM_NEUTRAL_FLAG : ~CSUM_NEUTRAL_FLAG); CSUM_NEUTRAL_FLAG : ~CSUM_NEUTRAL_FLAG);
...@@ -53,13 +60,23 @@ static void ila_csum_do_neutral(struct ila_addr *iaddr, ...@@ -53,13 +60,23 @@ static void ila_csum_do_neutral(struct ila_addr *iaddr,
iaddr->ident.csum_neutral ^= 1; iaddr->ident.csum_neutral ^= 1;
} }
static void ila_csum_adjust_transport(struct sk_buff *skb, static void ila_csum_do_neutral_nofmt(struct ila_addr *iaddr,
struct ila_params *p) struct ila_params *p)
{ {
__sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3];
__wsum diff; __wsum diff;
struct ipv6hdr *ip6h = ipv6_hdr(skb);
struct ila_addr *iaddr = ila_a2i(&ip6h->daddr); 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)
{
size_t nhoff = sizeof(struct ipv6hdr); size_t nhoff = sizeof(struct ipv6hdr);
struct ipv6hdr *ip6h = ipv6_hdr(skb);
__wsum diff;
switch (ip6h->nexthdr) { switch (ip6h->nexthdr) {
case NEXTHDR_TCP: case NEXTHDR_TCP:
...@@ -98,52 +115,45 @@ static void ila_csum_adjust_transport(struct sk_buff *skb, ...@@ -98,52 +115,45 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
} }
break; break;
} }
/* Now change destination address */
iaddr->loc = p->locator;
} }
void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p, 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 ipv6hdr *ip6h = ipv6_hdr(skb);
struct ila_addr *iaddr = ila_a2i(&ip6h->daddr); 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) { switch (p->csum_mode) {
case ILA_CSUM_ADJUST_TRANSPORT: case ILA_CSUM_ADJUST_TRANSPORT:
ila_csum_adjust_transport(skb, p); ila_csum_adjust_transport(skb, p);
break; break;
case ILA_CSUM_NEUTRAL_MAP: case ILA_CSUM_NEUTRAL_MAP:
ila_csum_do_neutral(iaddr, p); if (sir2ila) {
if (WARN_ON(ila_csum_neutral_set(iaddr->ident))) {
/* Checksum flag should never be
* set in a formatted SIR address.
*/
break; break;
case ILA_CSUM_NO_ACTION: }
} else if (!ila_csum_neutral_set(iaddr->ident)) {
/* ILA to SIR translation and C-bit isn't
* set so we're good.
*/
break; 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 */ /* Now change destination address */
iaddr->loc = p->locator; iaddr->loc = p->locator;
} }
void ila_init_saved_csum(struct ila_params *p)
{
if (!p->locator_match.v64)
return;
p->csum_diff = compute_csum_diff8(
(__be32 *)&p->locator,
(__be32 *)&p->locator_match);
}
static int __init ila_init(void) static int __init ila_init(void)
{ {
int ret; int ret;
......
...@@ -20,6 +20,7 @@ struct ila_lwt { ...@@ -20,6 +20,7 @@ struct ila_lwt {
struct ila_params p; struct ila_params p;
struct dst_cache dst_cache; struct dst_cache dst_cache;
u32 connected : 1; u32 connected : 1;
u32 lwt_output : 1;
}; };
static inline struct ila_lwt *ila_lwt_lwtunnel( static inline struct ila_lwt *ila_lwt_lwtunnel(
...@@ -45,7 +46,9 @@ static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb) ...@@ -45,7 +46,9 @@ static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb)
if (skb->protocol != htons(ETH_P_IPV6)) if (skb->protocol != htons(ETH_P_IPV6))
goto drop; goto drop;
ila_update_ipv6_locator(skb, ila_params_lwtunnel(orig_dst->lwtstate), if (ilwt->lwt_output)
ila_update_ipv6_locator(skb,
ila_params_lwtunnel(orig_dst->lwtstate),
true); true);
if (rt->rt6i_flags & (RTF_GATEWAY | RTF_CACHE)) { if (rt->rt6i_flags & (RTF_GATEWAY | RTF_CACHE)) {
...@@ -98,11 +101,15 @@ static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb) ...@@ -98,11 +101,15 @@ static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb)
static int ila_input(struct sk_buff *skb) static int ila_input(struct sk_buff *skb)
{ {
struct dst_entry *dst = skb_dst(skb); struct dst_entry *dst = skb_dst(skb);
struct ila_lwt *ilwt = ila_lwt_lwtunnel(dst->lwtstate);
if (skb->protocol != htons(ETH_P_IPV6)) if (skb->protocol != htons(ETH_P_IPV6))
goto drop; goto drop;
ila_update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate), false); if (!ilwt->lwt_output)
ila_update_ipv6_locator(skb,
ila_params_lwtunnel(dst->lwtstate),
false);
return dst->lwtstate->orig_input(skb); return dst->lwtstate->orig_input(skb);
...@@ -114,6 +121,8 @@ static int ila_input(struct sk_buff *skb) ...@@ -114,6 +121,8 @@ static int ila_input(struct sk_buff *skb)
static const struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = { static const struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
[ILA_ATTR_LOCATOR] = { .type = NLA_U64, }, [ILA_ATTR_LOCATOR] = { .type = NLA_U64, },
[ILA_ATTR_CSUM_MODE] = { .type = NLA_U8, }, [ILA_ATTR_CSUM_MODE] = { .type = NLA_U8, },
[ILA_ATTR_IDENT_TYPE] = { .type = NLA_U8, },
[ILA_ATTR_HOOK_TYPE] = { .type = NLA_U8, },
}; };
static int ila_build_state(struct nlattr *nla, static int ila_build_state(struct nlattr *nla,
...@@ -127,11 +136,33 @@ static int ila_build_state(struct nlattr *nla, ...@@ -127,11 +136,33 @@ static int ila_build_state(struct nlattr *nla,
struct lwtunnel_state *newts; struct lwtunnel_state *newts;
const struct fib6_config *cfg6 = cfg; const struct fib6_config *cfg6 = cfg;
struct ila_addr *iaddr; struct ila_addr *iaddr;
u8 ident_type = ILA_ATYPE_USE_FORMAT;
u8 hook_type = ILA_HOOK_ROUTE_OUTPUT;
u8 csum_mode = ILA_CSUM_NO_ACTION;
bool lwt_output = true;
u8 eff_ident_type;
int ret; int ret;
if (family != AF_INET6) if (family != AF_INET6)
return -EINVAL; return -EINVAL;
ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack);
if (ret < 0)
return ret;
if (!tb[ILA_ATTR_LOCATOR])
return -EINVAL;
iaddr = (struct ila_addr *)&cfg6->fc_dst;
if (tb[ILA_ATTR_IDENT_TYPE])
ident_type = nla_get_u8(tb[ILA_ATTR_IDENT_TYPE]);
if (ident_type == ILA_ATYPE_USE_FORMAT) {
/* Infer identifier type from type field in formatted
* identifier.
*/
if (cfg6->fc_dst_len < 8 * sizeof(struct ila_locator) + 3) { if (cfg6->fc_dst_len < 8 * sizeof(struct ila_locator) + 3) {
/* Need to have full locator and at least type field /* Need to have full locator and at least type field
* included in destination * included in destination
...@@ -139,21 +170,50 @@ static int ila_build_state(struct nlattr *nla, ...@@ -139,21 +170,50 @@ static int ila_build_state(struct nlattr *nla,
return -EINVAL; return -EINVAL;
} }
iaddr = (struct ila_addr *)&cfg6->fc_dst; eff_ident_type = iaddr->ident.type;
} else {
eff_ident_type = ident_type;
}
if (!ila_addr_is_ila(iaddr) || ila_csum_neutral_set(iaddr->ident)) { switch (eff_ident_type) {
/* Don't allow translation for a non-ILA address or checksum case ILA_ATYPE_IID:
* neutral flag to be set. /* Don't allow ILA for IID type */
*/ return -EINVAL;
case ILA_ATYPE_LUID:
break;
case ILA_ATYPE_VIRT_V4:
case ILA_ATYPE_VIRT_UNI_V6:
case ILA_ATYPE_VIRT_MULTI_V6:
case ILA_ATYPE_NONLOCAL_ADDR:
/* These ILA formats are not supported yet. */
default:
return -EINVAL; return -EINVAL;
} }
ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy, extack); if (tb[ILA_ATTR_HOOK_TYPE])
if (ret < 0) hook_type = nla_get_u8(tb[ILA_ATTR_HOOK_TYPE]);
return ret;
switch (hook_type) {
case ILA_HOOK_ROUTE_OUTPUT:
lwt_output = true;
break;
case ILA_HOOK_ROUTE_INPUT:
lwt_output = false;
break;
default:
return -EINVAL;
}
if (!tb[ILA_ATTR_LOCATOR]) 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; return -EINVAL;
}
newts = lwtunnel_state_alloc(sizeof(*ilwt)); newts = lwtunnel_state_alloc(sizeof(*ilwt));
if (!newts) if (!newts)
...@@ -166,19 +226,18 @@ static int ila_build_state(struct nlattr *nla, ...@@ -166,19 +226,18 @@ static int ila_build_state(struct nlattr *nla,
return ret; return ret;
} }
ilwt->lwt_output = !!lwt_output;
p = ila_params_lwtunnel(newts); p = ila_params_lwtunnel(newts);
p->csum_mode = csum_mode;
p->ident_type = ident_type;
p->locator.v64 = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]); p->locator.v64 = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]);
/* Precompute checksum difference for translation since we /* Precompute checksum difference for translation since we
* know both the old locator and the new one. * know both the old locator and the new one.
*/ */
p->locator_match = iaddr->loc; 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); ila_init_saved_csum(p);
...@@ -203,13 +262,23 @@ static int ila_fill_encap_info(struct sk_buff *skb, ...@@ -203,13 +262,23 @@ static int ila_fill_encap_info(struct sk_buff *skb,
struct lwtunnel_state *lwtstate) struct lwtunnel_state *lwtstate)
{ {
struct ila_params *p = ila_params_lwtunnel(lwtstate); struct ila_params *p = ila_params_lwtunnel(lwtstate);
struct ila_lwt *ilwt = ila_lwt_lwtunnel(lwtstate);
if (nla_put_u64_64bit(skb, ILA_ATTR_LOCATOR, (__force u64)p->locator.v64, if (nla_put_u64_64bit(skb, ILA_ATTR_LOCATOR, (__force u64)p->locator.v64,
ILA_ATTR_PAD)) ILA_ATTR_PAD))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u8(skb, ILA_ATTR_CSUM_MODE, (__force u8)p->csum_mode)) if (nla_put_u8(skb, ILA_ATTR_CSUM_MODE, (__force u8)p->csum_mode))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u8(skb, ILA_ATTR_IDENT_TYPE, (__force u8)p->ident_type))
goto nla_put_failure;
if (nla_put_u8(skb, ILA_ATTR_HOOK_TYPE,
ilwt->lwt_output ? ILA_HOOK_ROUTE_OUTPUT :
ILA_HOOK_ROUTE_INPUT))
goto nla_put_failure;
return 0; return 0;
nla_put_failure: nla_put_failure:
...@@ -220,6 +289,8 @@ static int ila_encap_nlsize(struct lwtunnel_state *lwtstate) ...@@ -220,6 +289,8 @@ static int ila_encap_nlsize(struct lwtunnel_state *lwtstate)
{ {
return nla_total_size_64bit(sizeof(u64)) + /* ILA_ATTR_LOCATOR */ return nla_total_size_64bit(sizeof(u64)) + /* ILA_ATTR_LOCATOR */
nla_total_size(sizeof(u8)) + /* ILA_ATTR_CSUM_MODE */ nla_total_size(sizeof(u8)) + /* ILA_ATTR_CSUM_MODE */
nla_total_size(sizeof(u8)) + /* ILA_ATTR_IDENT_TYPE */
nla_total_size(sizeof(u8)) + /* ILA_ATTR_HOOK_TYPE */
0; 0;
} }
......
...@@ -121,6 +121,7 @@ static const struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = { ...@@ -121,6 +121,7 @@ static const struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
[ILA_ATTR_LOCATOR_MATCH] = { .type = NLA_U64, }, [ILA_ATTR_LOCATOR_MATCH] = { .type = NLA_U64, },
[ILA_ATTR_IFINDEX] = { .type = NLA_U32, }, [ILA_ATTR_IFINDEX] = { .type = NLA_U32, },
[ILA_ATTR_CSUM_MODE] = { .type = NLA_U8, }, [ILA_ATTR_CSUM_MODE] = { .type = NLA_U8, },
[ILA_ATTR_IDENT_TYPE] = { .type = NLA_U8, },
}; };
static int parse_nl_config(struct genl_info *info, static int parse_nl_config(struct genl_info *info,
...@@ -138,6 +139,14 @@ static int parse_nl_config(struct genl_info *info, ...@@ -138,6 +139,14 @@ static int parse_nl_config(struct genl_info *info,
if (info->attrs[ILA_ATTR_CSUM_MODE]) if (info->attrs[ILA_ATTR_CSUM_MODE])
xp->ip.csum_mode = nla_get_u8(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_IDENT_TYPE])
xp->ip.ident_type = nla_get_u8(
info->attrs[ILA_ATTR_IDENT_TYPE]);
else
xp->ip.ident_type = ILA_ATYPE_USE_FORMAT;
if (info->attrs[ILA_ATTR_IFINDEX]) if (info->attrs[ILA_ATTR_IFINDEX])
xp->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]); xp->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]);
...@@ -198,7 +207,7 @@ static void ila_free_cb(void *ptr, void *arg) ...@@ -198,7 +207,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 static unsigned int
ila_nf_input(void *priv, ila_nf_input(void *priv,
...@@ -396,7 +405,8 @@ static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg) ...@@ -396,7 +405,8 @@ static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg)
(__force u64)ila->xp.ip.locator_match.v64, (__force u64)ila->xp.ip.locator_match.v64,
ILA_ATTR_PAD) || ILA_ATTR_PAD) ||
nla_put_s32(msg, ILA_ATTR_IFINDEX, ila->xp.ifindex) || 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) ||
nla_put_u8(msg, ILA_ATTR_IDENT_TYPE, ila->xp.ip.ident_type))
return -1; return -1;
return 0; return 0;
...@@ -607,7 +617,7 @@ static struct pernet_operations ila_net_ops = { ...@@ -607,7 +617,7 @@ static struct pernet_operations ila_net_ops = {
.size = sizeof(struct ila_net), .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 ila_map *ila;
struct ipv6hdr *ip6h = ipv6_hdr(skb); struct ipv6hdr *ip6h = ipv6_hdr(skb);
...@@ -617,16 +627,16 @@ static int ila_xlat_addr(struct sk_buff *skb, bool set_csum_neutral) ...@@ -617,16 +627,16 @@ static int ila_xlat_addr(struct sk_buff *skb, bool set_csum_neutral)
/* Assumes skb contains a valid IPv6 header that is pulled */ /* Assumes skb contains a valid IPv6 header that is pulled */
if (!ila_addr_is_ila(iaddr)) { /* No check here that ILA type in the mapping matches what is in the
/* Type indicates this is not an ILA address */ * address. We assume that whatever sender gaves us can be translated.
return 0; * The checksum mode however is relevant.
} */
rcu_read_lock(); rcu_read_lock();
ila = ila_lookup_wildcards(iaddr, skb->dev->ifindex, ilan); ila = ila_lookup_wildcards(iaddr, skb->dev->ifindex, ilan);
if (ila) 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(); rcu_read_unlock();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment