blob: c3078d0b64e1ff4ca631979ed27442ca7738cf54 [file] [log] [blame]
Tom Herbert33f11d12015-12-15 15:41:35 -08001#include <linux/errno.h>
2#include <linux/ip.h>
3#include <linux/kernel.h>
4#include <linux/module.h>
5#include <linux/skbuff.h>
6#include <linux/socket.h>
7#include <linux/types.h>
8#include <net/checksum.h>
9#include <net/ip.h>
10#include <net/ip6_fib.h>
11#include <net/lwtunnel.h>
12#include <net/protocol.h>
13#include <uapi/linux/ila.h>
14#include "ila.h"
15
16static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p)
17{
Tom Herbert351596a2016-04-23 11:46:55 -070018 struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
19
20 if (iaddr->loc.v64 == p->locator_match.v64)
Tom Herbert33f11d12015-12-15 15:41:35 -080021 return p->csum_diff;
22 else
Tom Herbert351596a2016-04-23 11:46:55 -070023 return compute_csum_diff8((__be32 *)&iaddr->loc,
Tom Herbert33f11d12015-12-15 15:41:35 -080024 (__be32 *)&p->locator);
25}
26
Tom Herbert351596a2016-04-23 11:46:55 -070027void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p)
Tom Herbert33f11d12015-12-15 15:41:35 -080028{
29 __wsum diff;
30 struct ipv6hdr *ip6h = ipv6_hdr(skb);
Tom Herbert351596a2016-04-23 11:46:55 -070031 struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
Tom Herbert33f11d12015-12-15 15:41:35 -080032 size_t nhoff = sizeof(struct ipv6hdr);
33
34 /* First update checksum */
35 switch (ip6h->nexthdr) {
36 case NEXTHDR_TCP:
37 if (likely(pskb_may_pull(skb, nhoff + sizeof(struct tcphdr)))) {
38 struct tcphdr *th = (struct tcphdr *)
39 (skb_network_header(skb) + nhoff);
40
41 diff = get_csum_diff(ip6h, p);
42 inet_proto_csum_replace_by_diff(&th->check, skb,
43 diff, true);
44 }
45 break;
46 case NEXTHDR_UDP:
47 if (likely(pskb_may_pull(skb, nhoff + sizeof(struct udphdr)))) {
48 struct udphdr *uh = (struct udphdr *)
49 (skb_network_header(skb) + nhoff);
50
51 if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
52 diff = get_csum_diff(ip6h, p);
53 inet_proto_csum_replace_by_diff(&uh->check, skb,
54 diff, true);
55 if (!uh->check)
56 uh->check = CSUM_MANGLED_0;
57 }
58 }
59 break;
60 case NEXTHDR_ICMP:
61 if (likely(pskb_may_pull(skb,
62 nhoff + sizeof(struct icmp6hdr)))) {
63 struct icmp6hdr *ih = (struct icmp6hdr *)
64 (skb_network_header(skb) + nhoff);
65
66 diff = get_csum_diff(ip6h, p);
67 inet_proto_csum_replace_by_diff(&ih->icmp6_cksum, skb,
68 diff, true);
69 }
70 break;
71 }
72
73 /* Now change destination address */
Tom Herbert351596a2016-04-23 11:46:55 -070074 iaddr->loc = p->locator;
Tom Herbert33f11d12015-12-15 15:41:35 -080075}
76
77static int __init ila_init(void)
78{
79 int ret;
80
81 ret = ila_lwt_init();
82
83 if (ret)
84 goto fail_lwt;
85
Tom Herbert7f00fea2015-12-15 15:41:38 -080086 ret = ila_xlat_init();
87 if (ret)
88 goto fail_xlat;
89
90 return 0;
91fail_xlat:
92 ila_lwt_fini();
Tom Herbert33f11d12015-12-15 15:41:35 -080093fail_lwt:
94 return ret;
95}
96
97static void __exit ila_fini(void)
98{
Tom Herbert7f00fea2015-12-15 15:41:38 -080099 ila_xlat_fini();
Tom Herbert33f11d12015-12-15 15:41:35 -0800100 ila_lwt_fini();
101}
102
103module_init(ila_init);
104module_exit(ila_fini);
Robert Shearman84a8cbe2016-02-19 09:43:18 +0000105MODULE_ALIAS_RTNL_LWT(ILA);
Tom Herbert33f11d12015-12-15 15:41:35 -0800106MODULE_AUTHOR("Tom Herbert <tom@herbertland.com>");
107MODULE_LICENSE("GPL");