~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/ila/ila_common.c

Version: ~ [ linux-5.4-rc3 ] ~ [ linux-5.3.6 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.79 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.149 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.196 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.196 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.75 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #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 
 16 static __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p)
 17 {
 18         struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
 19 
 20         if (p->locator_match.v64)
 21                 return p->csum_diff;
 22         else
 23                 return compute_csum_diff8((__be32 *)&iaddr->loc,
 24                                           (__be32 *)&p->locator);
 25 }
 26 
 27 static 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 *)&p->locator,
 38                                           (__be32 *)iaddr);
 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;
 54 }
 55 
 56 static void ila_csum_adjust_transport(struct sk_buff *skb,
 57                                       struct ila_params *p)
 58 {
 59         __wsum diff;
 60         struct ipv6hdr *ip6h = ipv6_hdr(skb);
 61         struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
 62         size_t nhoff = sizeof(struct ipv6hdr);
 63 
 64         switch (ip6h->nexthdr) {
 65         case NEXTHDR_TCP:
 66                 if (likely(pskb_may_pull(skb, nhoff + sizeof(struct tcphdr)))) {
 67                         struct tcphdr *th = (struct tcphdr *)
 68                                         (skb_network_header(skb) + nhoff);
 69 
 70                         diff = get_csum_diff(ip6h, p);
 71                         inet_proto_csum_replace_by_diff(&th->check, skb,
 72                                                         diff, true);
 73                 }
 74                 break;
 75         case NEXTHDR_UDP:
 76                 if (likely(pskb_may_pull(skb, nhoff + sizeof(struct udphdr)))) {
 77                         struct udphdr *uh = (struct udphdr *)
 78                                         (skb_network_header(skb) + nhoff);
 79 
 80                         if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
 81                                 diff = get_csum_diff(ip6h, p);
 82                                 inet_proto_csum_replace_by_diff(&uh->check, skb,
 83                                                                 diff, true);
 84                                 if (!uh->check)
 85                                         uh->check = CSUM_MANGLED_0;
 86                         }
 87                 }
 88                 break;
 89         case NEXTHDR_ICMP:
 90                 if (likely(pskb_may_pull(skb,
 91                                          nhoff + sizeof(struct icmp6hdr)))) {
 92                         struct icmp6hdr *ih = (struct icmp6hdr *)
 93                                         (skb_network_header(skb) + nhoff);
 94 
 95                         diff = get_csum_diff(ip6h, p);
 96                         inet_proto_csum_replace_by_diff(&ih->icmp6_cksum, skb,
 97                                                         diff, true);
 98                 }
 99                 break;
100         }
101 
102         /* Now change destination address */
103         iaddr->loc = p->locator;
104 }
105 
106 void ila_update_ipv6_locator(struct sk_buff *skb, struct ila_params *p,
107                              bool set_csum_neutral)
108 {
109         struct ipv6hdr *ip6h = ipv6_hdr(skb);
110         struct ila_addr *iaddr = ila_a2i(&ip6h->daddr);
111 
112         /* First deal with the transport checksum */
113         if (ila_csum_neutral_set(iaddr->ident)) {
114                 /* C-bit is set in the locator indicating that this
115                  * is a locator being translated to a SIR address.
116                  * Perform (receiver) checksum-neutral translation.
117                  */
118                 if (!set_csum_neutral)
119                         ila_csum_do_neutral(iaddr, p);
120         } else {
121                 switch (p->csum_mode) {
122                 case ILA_CSUM_ADJUST_TRANSPORT:
123                         ila_csum_adjust_transport(skb, p);
124                         break;
125                 case ILA_CSUM_NEUTRAL_MAP:
126                         ila_csum_do_neutral(iaddr, p);
127                         break;
128                 case ILA_CSUM_NO_ACTION:
129                         break;
130                 }
131         }
132 
133         /* Now change destination address */
134         iaddr->loc = p->locator;
135 }
136 
137 void ila_init_saved_csum(struct ila_params *p)
138 {
139         if (!p->locator_match.v64)
140                 return;
141 
142         p->csum_diff = compute_csum_diff8(
143                                 (__be32 *)&p->locator,
144                                 (__be32 *)&p->locator_match);
145 }
146 
147 static int __init ila_init(void)
148 {
149         int ret;
150 
151         ret = ila_lwt_init();
152 
153         if (ret)
154                 goto fail_lwt;
155 
156         ret = ila_xlat_init();
157         if (ret)
158                 goto fail_xlat;
159 
160         return 0;
161 fail_xlat:
162         ila_lwt_fini();
163 fail_lwt:
164         return ret;
165 }
166 
167 static void __exit ila_fini(void)
168 {
169         ila_xlat_fini();
170         ila_lwt_fini();
171 }
172 
173 module_init(ila_init);
174 module_exit(ila_fini);
175 MODULE_AUTHOR("Tom Herbert <tom@herbertland.com>");
176 MODULE_LICENSE("GPL");
177 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp