aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/ila/ila.h79
-rw-r--r--net/ipv6/ila/ila_common.c81
-rw-r--r--net/ipv6/ila/ila_lwt.c49
-rw-r--r--net/ipv6/ila/ila_xlat.c161
4 files changed, 252 insertions, 118 deletions
diff --git a/net/ipv6/ila/ila.h b/net/ipv6/ila/ila.h
index 28542cb2b387..d08fd2d48a78 100644
--- a/net/ipv6/ila/ila.h
+++ b/net/ipv6/ila/ila.h
@@ -23,10 +23,76 @@
23#include <net/protocol.h> 23#include <net/protocol.h>
24#include <uapi/linux/ila.h> 24#include <uapi/linux/ila.h>
25 25
26struct ila_locator {
27 union {
28 __u8 v8[8];
29 __be16 v16[4];
30 __be32 v32[2];
31 __be64 v64;
32 };
33};
34
35struct ila_identifier {
36 union {
37 struct {
38#if defined(__LITTLE_ENDIAN_BITFIELD)
39 u8 __space:4;
40 u8 csum_neutral:1;
41 u8 type:3;
42#elif defined(__BIG_ENDIAN_BITFIELD)
43 u8 type:3;
44 u8 csum_neutral:1;
45 u8 __space:4;
46#else
47#error "Adjust your <asm/byteorder.h> defines"
48#endif
49 u8 __space2[7];
50 };
51 __u8 v8[8];
52 __be16 v16[4];
53 __be32 v32[2];
54 __be64 v64;
55 };
56};
57
58enum {
59 ILA_ATYPE_IID = 0,
60 ILA_ATYPE_LUID,
61 ILA_ATYPE_VIRT_V4,
62 ILA_ATYPE_VIRT_UNI_V6,
63 ILA_ATYPE_VIRT_MULTI_V6,
64 ILA_ATYPE_RSVD_1,
65 ILA_ATYPE_RSVD_2,
66 ILA_ATYPE_RSVD_3,
67};
68
69#define CSUM_NEUTRAL_FLAG htonl(0x10000000)
70
71struct ila_addr {
72 union {
73 struct in6_addr addr;
74 struct {
75 struct ila_locator loc;
76 struct ila_identifier ident;
77 };
78 };
79};
80
81static inline struct ila_addr *ila_a2i(struct in6_addr *addr)
82{
83 return (struct ila_addr *)addr;
84}
85
86static inline bool ila_addr_is_ila(struct ila_addr *iaddr)
87{
88 return (iaddr->ident.type != ILA_ATYPE_IID);
89}
90
26struct ila_params { 91struct ila_params {
27 __be64 locator; 92 struct ila_locator locator;
28 __be64 locator_match; 93 struct ila_locator locator_match;
29 __wsum csum_diff; 94 __wsum csum_diff;
95 u8 csum_mode;
30}; 96};
31 97
32static inline __wsum compute_csum_diff8(const __be32 *from, const __be32 *to) 98static inline __wsum compute_csum_diff8(const __be32 *from, const __be32 *to)
@@ -38,7 +104,14 @@ static inline __wsum compute_csum_diff8(const __be32 *from, const __be32 *to)
38 return csum_partial(diff, sizeof(diff), 0); 104 return csum_partial(diff, sizeof(diff), 0);
39} 105}
40 106
41void update_ipv6_locator(struct sk_buff *skb, struct ila_params *p); 107static inline bool ila_csum_neutral_set(struct ila_identifier ident)
108{
109 return !!(ident.csum_neutral);
110}
111
112void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p);
113
114void ila_init_saved_csum(struct ila_params *p);
42 115
43int ila_lwt_init(void); 116int ila_lwt_init(void);
44void ila_lwt_fini(void); 117void ila_lwt_fini(void);
diff --git a/net/ipv6/ila/ila_common.c b/net/ipv6/ila/ila_common.c
index 30613050e4ca..0e94042d1289 100644
--- a/net/ipv6/ila/ila_common.c
+++ b/net/ipv6/ila/ila_common.c
@@ -15,20 +15,52 @@
15 15
16static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p) 16static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p)
17{ 17{
18 if (*(__be64 *)&ip6h->daddr == p->locator_match) 18 struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
19
20 if (p->locator_match.v64)
19 return p->csum_diff; 21 return p->csum_diff;
20 else 22 else
21 return compute_csum_diff8((__be32 *)&ip6h->daddr, 23 return compute_csum_diff8((__be32 *)&iaddr->loc,
24 (__be32 *)&p->locator);
25}
26
27static void ila_csum_do_neutral(struct ila_addr *iaddr,
28 struct ila_params *p)
29{
30 __sum16 *adjust = (__force __sum16 *)&iaddr->ident.v16[3];
31 __wsum diff, fval;
32
33 /* Check if checksum adjust value has been cached */
34 if (p->locator_match.v64) {
35 diff = p->csum_diff;
36 } else {
37 diff = compute_csum_diff8((__be32 *)iaddr,
22 (__be32 *)&p->locator); 38 (__be32 *)&p->locator);
39 }
40
41 fval = (__force __wsum)(ila_csum_neutral_set(iaddr->ident) ?
42 ~CSUM_NEUTRAL_FLAG : CSUM_NEUTRAL_FLAG);
43
44 diff = csum_add(diff, fval);
45
46 *adjust = ~csum_fold(csum_add(diff, csum_unfold(*adjust)));
47
48 /* Flip the csum-neutral bit. Either we are doing a SIR->ILA
49 * translation with ILA_CSUM_NEUTRAL_MAP as the csum_method
50 * and the C-bit is not set, or we are doing an ILA-SIR
51 * tranlsation and the C-bit is set.
52 */
53 iaddr->ident.csum_neutral ^= 1;
23} 54}
24 55
25void update_ipv6_locator(struct sk_buff *skb, struct ila_params *p) 56static void ila_csum_adjust_transport(struct sk_buff *skb,
57 struct ila_params *p)
26{ 58{
27 __wsum diff; 59 __wsum diff;
28 struct ipv6hdr *ip6h = ipv6_hdr(skb); 60 struct ipv6hdr *ip6h = ipv6_hdr(skb);
61 struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
29 size_t nhoff = sizeof(struct ipv6hdr); 62 size_t nhoff = sizeof(struct ipv6hdr);
30 63
31 /* First update checksum */
32 switch (ip6h->nexthdr) { 64 switch (ip6h->nexthdr) {
33 case NEXTHDR_TCP: 65 case NEXTHDR_TCP:
34 if (likely(pskb_may_pull(skb, nhoff + sizeof(struct tcphdr)))) { 66 if (likely(pskb_may_pull(skb, nhoff + sizeof(struct tcphdr)))) {
@@ -68,7 +100,46 @@ void update_ipv6_locator(struct sk_buff *skb, struct ila_params *p)
68 } 100 }
69 101
70 /* Now change destination address */ 102 /* Now change destination address */
71 *(__be64 *)&ip6h->daddr = p->locator; 103 iaddr->loc = p->locator;
104}
105
106void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p)
107{
108 struct ipv6hdr *ip6h = ipv6_hdr(skb);
109 struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
110
111 /* First deal with the transport checksum */
112 if (ila_csum_neutral_set(iaddr->ident)) {
113 /* C-bit is set in the locator indicating that this
114 * is a locator being translated to a SIR address.
115 * Perform (receiver) checksum-neutral translation.
116 */
117 ila_csum_do_neutral(iaddr, p);
118 } else {
119 switch (p->csum_mode) {
120 case ILA_CSUM_ADJUST_TRANSPORT:
121 ila_csum_adjust_transport(skb, p);
122 break;
123 case ILA_CSUM_NEUTRAL_MAP:
124 ila_csum_do_neutral(iaddr, p);
125 break;
126 case ILA_CSUM_NO_ACTION:
127 break;
128 }
129 }
130
131 /* Now change destination address */
132 iaddr->loc = p->locator;
133}
134
135void ila_init_saved_csum(struct ila_params *p)
136{
137 if (!p->locator_match.v64)
138 return;
139
140 p->csum_diff = compute_csum_diff8(
141 (__be32 *)&p->locator_match,
142 (__be32 *)&p->locator);
72} 143}
73 144
74static int __init ila_init(void) 145static int __init ila_init(void)
diff --git a/net/ipv6/ila/ila_lwt.c b/net/ipv6/ila/ila_lwt.c
index 9db3621b2126..4985e1a735a6 100644
--- a/net/ipv6/ila/ila_lwt.c
+++ b/net/ipv6/ila/ila_lwt.c
@@ -26,7 +26,7 @@ static int ila_output(struct net *net, struct sock *sk, struct sk_buff *skb)
26 if (skb->protocol != htons(ETH_P_IPV6)) 26 if (skb->protocol != htons(ETH_P_IPV6))
27 goto drop; 27 goto drop;
28 28
29 update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate)); 29 ila_update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate));
30 30
31 return dst->lwtstate->orig_output(net, sk, skb); 31 return dst->lwtstate->orig_output(net, sk, skb);
32 32
@@ -42,7 +42,7 @@ static int ila_input(struct sk_buff *skb)
42 if (skb->protocol != htons(ETH_P_IPV6)) 42 if (skb->protocol != htons(ETH_P_IPV6))
43 goto drop; 43 goto drop;
44 44
45 update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate)); 45 ila_update_ipv6_locator(skb, ila_params_lwtunnel(dst->lwtstate));
46 46
47 return dst->lwtstate->orig_input(skb); 47 return dst->lwtstate->orig_input(skb);
48 48
@@ -53,6 +53,7 @@ drop:
53 53
54static struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = { 54static struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
55 [ILA_ATTR_LOCATOR] = { .type = NLA_U64, }, 55 [ILA_ATTR_LOCATOR] = { .type = NLA_U64, },
56 [ILA_ATTR_CSUM_MODE] = { .type = NLA_U8, },
56}; 57};
57 58
58static int ila_build_state(struct net_device *dev, struct nlattr *nla, 59static int ila_build_state(struct net_device *dev, struct nlattr *nla,
@@ -64,11 +65,28 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla,
64 size_t encap_len = sizeof(*p); 65 size_t encap_len = sizeof(*p);
65 struct lwtunnel_state *newts; 66 struct lwtunnel_state *newts;
66 const struct fib6_config *cfg6 = cfg; 67 const struct fib6_config *cfg6 = cfg;
68 struct ila_addr *iaddr;
67 int ret; 69 int ret;
68 70
69 if (family != AF_INET6) 71 if (family != AF_INET6)
70 return -EINVAL; 72 return -EINVAL;
71 73
74 if (cfg6->fc_dst_len < sizeof(struct ila_locator) + 1) {
75 /* Need to have full locator and at least type field
76 * included in destination
77 */
78 return -EINVAL;
79 }
80
81 iaddr = (struct ila_addr *)&cfg6->fc_dst;
82
83 if (!ila_addr_is_ila(iaddr) || ila_csum_neutral_set(iaddr->ident)) {
84 /* Don't allow translation for a non-ILA address or checksum
85 * neutral flag to be set.
86 */
87 return -EINVAL;
88 }
89
72 ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, 90 ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla,
73 ila_nl_policy); 91 ila_nl_policy);
74 if (ret < 0) 92 if (ret < 0)
@@ -84,16 +102,19 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla,
84 newts->len = encap_len; 102 newts->len = encap_len;
85 p = ila_params_lwtunnel(newts); 103 p = ila_params_lwtunnel(newts);
86 104
87 p->locator = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]); 105 p->locator.v64 = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]);
88 106
89 if (cfg6->fc_dst_len > sizeof(__be64)) { 107 /* Precompute checksum difference for translation since we
90 /* Precompute checksum difference for translation since we 108 * know both the old locator and the new one.
91 * know both the old locator and the new one. 109 */
92 */ 110 p->locator_match = iaddr->loc;
93 p->locator_match = *(__be64 *)&cfg6->fc_dst; 111 p->csum_diff = compute_csum_diff8(
94 p->csum_diff = compute_csum_diff8( 112 (__be32 *)&p->locator_match, (__be32 *)&p->locator);
95 (__be32 *)&p->locator_match, (__be32 *)&p->locator); 113
96 } 114 if (tb[ILA_ATTR_CSUM_MODE])
115 p->csum_mode = nla_get_u8(tb[ILA_ATTR_CSUM_MODE]);
116
117 ila_init_saved_csum(p);
97 118
98 newts->type = LWTUNNEL_ENCAP_ILA; 119 newts->type = LWTUNNEL_ENCAP_ILA;
99 newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT | 120 newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT |
@@ -109,9 +130,11 @@ static int ila_fill_encap_info(struct sk_buff *skb,
109{ 130{
110 struct ila_params *p = ila_params_lwtunnel(lwtstate); 131 struct ila_params *p = ila_params_lwtunnel(lwtstate);
111 132
112 if (nla_put_u64_64bit(skb, ILA_ATTR_LOCATOR, (__force u64)p->locator, 133 if (nla_put_u64_64bit(skb, ILA_ATTR_LOCATOR, (__force u64)p->locator.v64,
113 ILA_ATTR_PAD)) 134 ILA_ATTR_PAD))
114 goto nla_put_failure; 135 goto nla_put_failure;
136 if (nla_put_u64(skb, ILA_ATTR_CSUM_MODE, (__force u8)p->csum_mode))
137 goto nla_put_failure;
115 138
116 return 0; 139 return 0;
117 140
@@ -130,7 +153,7 @@ static int ila_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b)
130 struct ila_params *a_p = ila_params_lwtunnel(a); 153 struct ila_params *a_p = ila_params_lwtunnel(a);
131 struct ila_params *b_p = ila_params_lwtunnel(b); 154 struct ila_params *b_p = ila_params_lwtunnel(b);
132 155
133 return (a_p->locator != b_p->locator); 156 return (a_p->locator.v64 != b_p->locator.v64);
134} 157}
135 158
136static const struct lwtunnel_encap_ops ila_encap_ops = { 159static const struct lwtunnel_encap_ops ila_encap_ops = {
diff --git a/net/ipv6/ila/ila_xlat.c b/net/ipv6/ila/ila_xlat.c
index 0e9e579410da..a90e57229c6c 100644
--- a/net/ipv6/ila/ila_xlat.c
+++ b/net/ipv6/ila/ila_xlat.c
@@ -11,13 +11,11 @@
11 11
12struct ila_xlat_params { 12struct ila_xlat_params {
13 struct ila_params ip; 13 struct ila_params ip;
14 __be64 identifier;
15 int ifindex; 14 int ifindex;
16 unsigned int dir;
17}; 15};
18 16
19struct ila_map { 17struct ila_map {
20 struct ila_xlat_params p; 18 struct ila_xlat_params xp;
21 struct rhash_head node; 19 struct rhash_head node;
22 struct ila_map __rcu *next; 20 struct ila_map __rcu *next;
23 struct rcu_head rcu; 21 struct rcu_head rcu;
@@ -66,31 +64,29 @@ static __always_inline void __ila_hash_secret_init(void)
66 net_get_random_once(&hashrnd, sizeof(hashrnd)); 64 net_get_random_once(&hashrnd, sizeof(hashrnd));
67} 65}
68 66
69static inline u32 ila_identifier_hash(__be64 identifier) 67static inline u32 ila_locator_hash(struct ila_locator loc)
70{ 68{
71 u32 *v = (u32 *)&identifier; 69 u32 *v = (u32 *)loc.v32;
72 70
73 return jhash_2words(v[0], v[1], hashrnd); 71 return jhash_2words(v[0], v[1], hashrnd);
74} 72}
75 73
76static inline spinlock_t *ila_get_lock(struct ila_net *ilan, __be64 identifier) 74static inline spinlock_t *ila_get_lock(struct ila_net *ilan,
75 struct ila_locator loc)
77{ 76{
78 return &ilan->locks[ila_identifier_hash(identifier) & ilan->locks_mask]; 77 return &ilan->locks[ila_locator_hash(loc) & ilan->locks_mask];
79} 78}
80 79
81static inline int ila_cmp_wildcards(struct ila_map *ila, __be64 loc, 80static inline int ila_cmp_wildcards(struct ila_map *ila,
82 int ifindex, unsigned int dir) 81 struct ila_addr *iaddr, int ifindex)
83{ 82{
84 return (ila->p.ip.locator_match && ila->p.ip.locator_match != loc) || 83 return (ila->xp.ifindex && ila->xp.ifindex != ifindex);
85 (ila->p.ifindex && ila->p.ifindex != ifindex) ||
86 !(ila->p.dir & dir);
87} 84}
88 85
89static inline int ila_cmp_params(struct ila_map *ila, struct ila_xlat_params *p) 86static inline int ila_cmp_params(struct ila_map *ila,
87 struct ila_xlat_params *xp)
90{ 88{
91 return (ila->p.ip.locator_match != p->ip.locator_match) || 89 return (ila->xp.ifindex != xp->ifindex);
92 (ila->p.ifindex != p->ifindex) ||
93 (ila->p.dir != p->dir);
94} 90}
95 91
96static int ila_cmpfn(struct rhashtable_compare_arg *arg, 92static int ila_cmpfn(struct rhashtable_compare_arg *arg,
@@ -98,17 +94,14 @@ static int ila_cmpfn(struct rhashtable_compare_arg *arg,
98{ 94{
99 const struct ila_map *ila = obj; 95 const struct ila_map *ila = obj;
100 96
101 return (ila->p.identifier != *(__be64 *)arg->key); 97 return (ila->xp.ip.locator_match.v64 != *(__be64 *)arg->key);
102} 98}
103 99
104static inline int ila_order(struct ila_map *ila) 100static inline int ila_order(struct ila_map *ila)
105{ 101{
106 int score = 0; 102 int score = 0;
107 103
108 if (ila->p.ip.locator_match) 104 if (ila->xp.ifindex)
109 score += 1 << 0;
110
111 if (ila->p.ifindex)
112 score += 1 << 1; 105 score += 1 << 1;
113 106
114 return score; 107 return score;
@@ -117,7 +110,7 @@ static inline int ila_order(struct ila_map *ila)
117static const struct rhashtable_params rht_params = { 110static const struct rhashtable_params rht_params = {
118 .nelem_hint = 1024, 111 .nelem_hint = 1024,
119 .head_offset = offsetof(struct ila_map, node), 112 .head_offset = offsetof(struct ila_map, node),
120 .key_offset = offsetof(struct ila_map, p.identifier), 113 .key_offset = offsetof(struct ila_map, xp.ip.locator_match),
121 .key_len = sizeof(u64), /* identifier */ 114 .key_len = sizeof(u64), /* identifier */
122 .max_size = 1048576, 115 .max_size = 1048576,
123 .min_size = 256, 116 .min_size = 256,
@@ -136,50 +129,45 @@ static struct genl_family ila_nl_family = {
136}; 129};
137 130
138static struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = { 131static struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
139 [ILA_ATTR_IDENTIFIER] = { .type = NLA_U64, },
140 [ILA_ATTR_LOCATOR] = { .type = NLA_U64, }, 132 [ILA_ATTR_LOCATOR] = { .type = NLA_U64, },
141 [ILA_ATTR_LOCATOR_MATCH] = { .type = NLA_U64, }, 133 [ILA_ATTR_LOCATOR_MATCH] = { .type = NLA_U64, },
142 [ILA_ATTR_IFINDEX] = { .type = NLA_U32, }, 134 [ILA_ATTR_IFINDEX] = { .type = NLA_U32, },
143 [ILA_ATTR_DIR] = { .type = NLA_U32, }, 135 [ILA_ATTR_CSUM_MODE] = { .type = NLA_U8, },
144}; 136};
145 137
146static int parse_nl_config(struct genl_info *info, 138static int parse_nl_config(struct genl_info *info,
147 struct ila_xlat_params *p) 139 struct ila_xlat_params *xp)
148{ 140{
149 memset(p, 0, sizeof(*p)); 141 memset(xp, 0, sizeof(*xp));
150
151 if (info->attrs[ILA_ATTR_IDENTIFIER])
152 p->identifier = (__force __be64)nla_get_u64(
153 info->attrs[ILA_ATTR_IDENTIFIER]);
154 142
155 if (info->attrs[ILA_ATTR_LOCATOR]) 143 if (info->attrs[ILA_ATTR_LOCATOR])
156 p->ip.locator = (__force __be64)nla_get_u64( 144 xp->ip.locator.v64 = (__force __be64)nla_get_u64(
157 info->attrs[ILA_ATTR_LOCATOR]); 145 info->attrs[ILA_ATTR_LOCATOR]);
158 146
159 if (info->attrs[ILA_ATTR_LOCATOR_MATCH]) 147 if (info->attrs[ILA_ATTR_LOCATOR_MATCH])
160 p->ip.locator_match = (__force __be64)nla_get_u64( 148 xp->ip.locator_match.v64 = (__force __be64)nla_get_u64(
161 info->attrs[ILA_ATTR_LOCATOR_MATCH]); 149 info->attrs[ILA_ATTR_LOCATOR_MATCH]);
162 150
163 if (info->attrs[ILA_ATTR_IFINDEX]) 151 if (info->attrs[ILA_ATTR_CSUM_MODE])
164 p->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]); 152 xp->ip.csum_mode = nla_get_u8(info->attrs[ILA_ATTR_CSUM_MODE]);
165 153
166 if (info->attrs[ILA_ATTR_DIR]) 154 if (info->attrs[ILA_ATTR_IFINDEX])
167 p->dir = nla_get_u32(info->attrs[ILA_ATTR_DIR]); 155 xp->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]);
168 156
169 return 0; 157 return 0;
170} 158}
171 159
172/* Must be called with rcu readlock */ 160/* Must be called with rcu readlock */
173static inline struct ila_map *ila_lookup_wildcards(__be64 id, __be64 loc, 161static inline struct ila_map *ila_lookup_wildcards(struct ila_addr *iaddr,
174 int ifindex, 162 int ifindex,
175 unsigned int dir,
176 struct ila_net *ilan) 163 struct ila_net *ilan)
177{ 164{
178 struct ila_map *ila; 165 struct ila_map *ila;
179 166
180 ila = rhashtable_lookup_fast(&ilan->rhash_table, &id, rht_params); 167 ila = rhashtable_lookup_fast(&ilan->rhash_table, &iaddr->loc,
168 rht_params);
181 while (ila) { 169 while (ila) {
182 if (!ila_cmp_wildcards(ila, loc, ifindex, dir)) 170 if (!ila_cmp_wildcards(ila, iaddr, ifindex))
183 return ila; 171 return ila;
184 ila = rcu_access_pointer(ila->next); 172 ila = rcu_access_pointer(ila->next);
185 } 173 }
@@ -188,15 +176,16 @@ static inline struct ila_map *ila_lookup_wildcards(__be64 id, __be64 loc,
188} 176}
189 177
190/* Must be called with rcu readlock */ 178/* Must be called with rcu readlock */
191static inline struct ila_map *ila_lookup_by_params(struct ila_xlat_params *p, 179static inline struct ila_map *ila_lookup_by_params(struct ila_xlat_params *xp,
192 struct ila_net *ilan) 180 struct ila_net *ilan)
193{ 181{
194 struct ila_map *ila; 182 struct ila_map *ila;
195 183
196 ila = rhashtable_lookup_fast(&ilan->rhash_table, &p->identifier, 184 ila = rhashtable_lookup_fast(&ilan->rhash_table,
185 &xp->ip.locator_match,
197 rht_params); 186 rht_params);
198 while (ila) { 187 while (ila) {
199 if (!ila_cmp_params(ila, p)) 188 if (!ila_cmp_params(ila, xp))
200 return ila; 189 return ila;
201 ila = rcu_access_pointer(ila->next); 190 ila = rcu_access_pointer(ila->next);
202 } 191 }
@@ -221,14 +210,14 @@ static void ila_free_cb(void *ptr, void *arg)
221 } 210 }
222} 211}
223 212
224static int ila_xlat_addr(struct sk_buff *skb, int dir); 213static int ila_xlat_addr(struct sk_buff *skb);
225 214
226static unsigned int 215static unsigned int
227ila_nf_input(void *priv, 216ila_nf_input(void *priv,
228 struct sk_buff *skb, 217 struct sk_buff *skb,
229 const struct nf_hook_state *state) 218 const struct nf_hook_state *state)
230{ 219{
231 ila_xlat_addr(skb, ILA_DIR_IN); 220 ila_xlat_addr(skb);
232 return NF_ACCEPT; 221 return NF_ACCEPT;
233} 222}
234 223
@@ -241,11 +230,11 @@ static struct nf_hook_ops ila_nf_hook_ops[] __read_mostly = {
241 }, 230 },
242}; 231};
243 232
244static int ila_add_mapping(struct net *net, struct ila_xlat_params *p) 233static int ila_add_mapping(struct net *net, struct ila_xlat_params *xp)
245{ 234{
246 struct ila_net *ilan = net_generic(net, ila_net_id); 235 struct ila_net *ilan = net_generic(net, ila_net_id);
247 struct ila_map *ila, *head; 236 struct ila_map *ila, *head;
248 spinlock_t *lock = ila_get_lock(ilan, p->identifier); 237 spinlock_t *lock = ila_get_lock(ilan, xp->ip.locator_match);
249 int err = 0, order; 238 int err = 0, order;
250 239
251 if (!ilan->hooks_registered) { 240 if (!ilan->hooks_registered) {
@@ -264,22 +253,16 @@ static int ila_add_mapping(struct net *net, struct ila_xlat_params *p)
264 if (!ila) 253 if (!ila)
265 return -ENOMEM; 254 return -ENOMEM;
266 255
267 ila->p = *p; 256 ila_init_saved_csum(&xp->ip);
268 257
269 if (p->ip.locator_match) { 258 ila->xp = *xp;
270 /* Precompute checksum difference for translation since we
271 * know both the old identifier and the new one.
272 */
273 ila->p.ip.csum_diff = compute_csum_diff8(
274 (__be32 *)&p->ip.locator_match,
275 (__be32 *)&p->ip.locator);
276 }
277 259
278 order = ila_order(ila); 260 order = ila_order(ila);
279 261
280 spin_lock(lock); 262 spin_lock(lock);
281 263
282 head = rhashtable_lookup_fast(&ilan->rhash_table, &p->identifier, 264 head = rhashtable_lookup_fast(&ilan->rhash_table,
265 &xp->ip.locator_match,
283 rht_params); 266 rht_params);
284 if (!head) { 267 if (!head) {
285 /* New entry for the rhash_table */ 268 /* New entry for the rhash_table */
@@ -289,7 +272,7 @@ static int ila_add_mapping(struct net *net, struct ila_xlat_params *p)
289 struct ila_map *tila = head, *prev = NULL; 272 struct ila_map *tila = head, *prev = NULL;
290 273
291 do { 274 do {
292 if (!ila_cmp_params(tila, p)) { 275 if (!ila_cmp_params(tila, xp)) {
293 err = -EEXIST; 276 err = -EEXIST;
294 goto out; 277 goto out;
295 } 278 }
@@ -326,23 +309,23 @@ out:
326 return err; 309 return err;
327} 310}
328 311
329static int ila_del_mapping(struct net *net, struct ila_xlat_params *p) 312static int ila_del_mapping(struct net *net, struct ila_xlat_params *xp)
330{ 313{
331 struct ila_net *ilan = net_generic(net, ila_net_id); 314 struct ila_net *ilan = net_generic(net, ila_net_id);
332 struct ila_map *ila, *head, *prev; 315 struct ila_map *ila, *head, *prev;
333 spinlock_t *lock = ila_get_lock(ilan, p->identifier); 316 spinlock_t *lock = ila_get_lock(ilan, xp->ip.locator_match);
334 int err = -ENOENT; 317 int err = -ENOENT;
335 318
336 spin_lock(lock); 319 spin_lock(lock);
337 320
338 head = rhashtable_lookup_fast(&ilan->rhash_table, 321 head = rhashtable_lookup_fast(&ilan->rhash_table,
339 &p->identifier, rht_params); 322 &xp->ip.locator_match, rht_params);
340 ila = head; 323 ila = head;
341 324
342 prev = NULL; 325 prev = NULL;
343 326
344 while (ila) { 327 while (ila) {
345 if (ila_cmp_params(ila, p)) { 328 if (ila_cmp_params(ila, xp)) {
346 prev = ila; 329 prev = ila;
347 ila = rcu_dereference_protected(ila->next, 330 ila = rcu_dereference_protected(ila->next,
348 lockdep_is_held(lock)); 331 lockdep_is_held(lock));
@@ -404,31 +387,28 @@ static int ila_nl_cmd_add_mapping(struct sk_buff *skb, struct genl_info *info)
404static int ila_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info) 387static int ila_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info)
405{ 388{
406 struct net *net = genl_info_net(info); 389 struct net *net = genl_info_net(info);
407 struct ila_xlat_params p; 390 struct ila_xlat_params xp;
408 int err; 391 int err;
409 392
410 err = parse_nl_config(info, &p); 393 err = parse_nl_config(info, &xp);
411 if (err) 394 if (err)
412 return err; 395 return err;
413 396
414 ila_del_mapping(net, &p); 397 ila_del_mapping(net, &xp);
415 398
416 return 0; 399 return 0;
417} 400}
418 401
419static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg) 402static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg)
420{ 403{
421 if (nla_put_u64_64bit(msg, ILA_ATTR_IDENTIFIER, 404 if (nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR,
422 (__force u64)ila->p.identifier, 405 (__force u64)ila->xp.ip.locator.v64,
423 ILA_ATTR_PAD) ||
424 nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR,
425 (__force u64)ila->p.ip.locator,
426 ILA_ATTR_PAD) || 406 ILA_ATTR_PAD) ||
427 nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR_MATCH, 407 nla_put_u64_64bit(msg, ILA_ATTR_LOCATOR_MATCH,
428 (__force u64)ila->p.ip.locator_match, 408 (__force u64)ila->xp.ip.locator_match.v64,
429 ILA_ATTR_PAD) || 409 ILA_ATTR_PAD) ||
430 nla_put_s32(msg, ILA_ATTR_IFINDEX, ila->p.ifindex) || 410 nla_put_s32(msg, ILA_ATTR_IFINDEX, ila->xp.ifindex) ||
431 nla_put_u32(msg, ILA_ATTR_DIR, ila->p.dir)) 411 nla_put_u32(msg, ILA_ATTR_CSUM_MODE, ila->xp.ip.csum_mode))
432 return -1; 412 return -1;
433 413
434 return 0; 414 return 0;
@@ -460,11 +440,11 @@ static int ila_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info)
460 struct net *net = genl_info_net(info); 440 struct net *net = genl_info_net(info);
461 struct ila_net *ilan = net_generic(net, ila_net_id); 441 struct ila_net *ilan = net_generic(net, ila_net_id);
462 struct sk_buff *msg; 442 struct sk_buff *msg;
463 struct ila_xlat_params p; 443 struct ila_xlat_params xp;
464 struct ila_map *ila; 444 struct ila_map *ila;
465 int ret; 445 int ret;
466 446
467 ret = parse_nl_config(info, &p); 447 ret = parse_nl_config(info, &xp);
468 if (ret) 448 if (ret)
469 return ret; 449 return ret;
470 450
@@ -474,7 +454,7 @@ static int ila_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info)
474 454
475 rcu_read_lock(); 455 rcu_read_lock();
476 456
477 ila = ila_lookup_by_params(&p, ilan); 457 ila = ila_lookup_by_params(&xp, ilan);
478 if (ila) { 458 if (ila) {
479 ret = ila_dump_info(ila, 459 ret = ila_dump_info(ila,
480 info->snd_portid, 460 info->snd_portid,
@@ -617,45 +597,32 @@ static struct pernet_operations ila_net_ops = {
617 .size = sizeof(struct ila_net), 597 .size = sizeof(struct ila_net),
618}; 598};
619 599
620static int ila_xlat_addr(struct sk_buff *skb, int dir) 600static int ila_xlat_addr(struct sk_buff *skb)
621{ 601{
622 struct ila_map *ila; 602 struct ila_map *ila;
623 struct ipv6hdr *ip6h = ipv6_hdr(skb); 603 struct ipv6hdr *ip6h = ipv6_hdr(skb);
624 struct net *net = dev_net(skb->dev); 604 struct net *net = dev_net(skb->dev);
625 struct ila_net *ilan = net_generic(net, ila_net_id); 605 struct ila_net *ilan = net_generic(net, ila_net_id);
626 __be64 identifier, locator_match; 606 struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
627 size_t nhoff;
628 607
629 /* Assumes skb contains a valid IPv6 header that is pulled */ 608 /* Assumes skb contains a valid IPv6 header that is pulled */
630 609
631 identifier = *(__be64 *)&ip6h->daddr.in6_u.u6_addr8[8]; 610 if (!ila_addr_is_ila(iaddr)) {
632 locator_match = *(__be64 *)&ip6h->daddr.in6_u.u6_addr8[0]; 611 /* Type indicates this is not an ILA address */
633 nhoff = sizeof(struct ipv6hdr); 612 return 0;
613 }
634 614
635 rcu_read_lock(); 615 rcu_read_lock();
636 616
637 ila = ila_lookup_wildcards(identifier, locator_match, 617 ila = ila_lookup_wildcards(iaddr, skb->dev->ifindex, ilan);
638 skb->dev->ifindex, dir, ilan);
639 if (ila) 618 if (ila)
640 update_ipv6_locator(skb, &ila->p.ip); 619 ila_update_ipv6_locator(skb, &ila->xp.ip);
641 620
642 rcu_read_unlock(); 621 rcu_read_unlock();
643 622
644 return 0; 623 return 0;
645} 624}
646 625
647int ila_xlat_incoming(struct sk_buff *skb)
648{
649 return ila_xlat_addr(skb, ILA_DIR_IN);
650}
651EXPORT_SYMBOL(ila_xlat_incoming);
652
653int ila_xlat_outgoing(struct sk_buff *skb)
654{
655 return ila_xlat_addr(skb, ILA_DIR_OUT);
656}
657EXPORT_SYMBOL(ila_xlat_outgoing);
658
659int ila_xlat_init(void) 626int ila_xlat_init(void)
660{ 627{
661 int ret; 628 int ret;