Fix tons of deprecation warnings
[samplevnf.git] / VNFs / DPPD-PROX / prox_ipv6.c
1 /*
2 // Copyright (c) 2020 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include "task_base.h"
18 #include "handle_master.h"
19 #include "prox_cfg.h"
20 #include "prox_ipv6.h"
21
22 struct ipv6_addr null_addr = {{0}};
23 char ip6_str[40]; // 8 blocks of 2 bytes (4 char) + 1x ":" between blocks
24
25 void set_mcast_mac_from_ipv6(prox_rte_ether_addr *mac, struct ipv6_addr *ipv6_addr)
26 {
27         mac->addr_bytes[0] = 0x33;
28         mac->addr_bytes[1] = 0x33;
29         memcpy(((uint32_t *)&mac->addr_bytes[2]), (uint32_t *)(&ipv6_addr->bytes[12]), sizeof(uint32_t));
30 }
31
32 // Note that this function is not Mthread safe and would result in garbage if called simultaneously from multiple threads
33 // This function is however only used for debugging, printing errors...
34 char *IP6_Canonical(struct ipv6_addr *addr)
35 {
36         uint8_t *a = (uint8_t *)addr;
37         char *ptr = ip6_str;
38         int field = -1, len = 0, stored_field = 0, stored_len = 0;
39
40         // Find longest run of consecutive 16-bit 0 fields
41         for (int i = 0; i < 8; i++) {
42                 if (((int)a[i * 2] == 0) && ((int)a[i * 2 + 1] == 0)) {
43                         len++;
44                         if (field == -1)
45                                 field = i;      // Store where the first 0 field started
46                 } else {
47                         if (len > stored_len) {
48                                 // the longest run of consecutive 16-bit 0 fields MUST be shortened
49                                 stored_len = len;
50                                 stored_field = field;
51                         }
52                         len = 0;
53                         field = -1;
54                 }
55         }
56         if (len > stored_len) {
57                 // the longest run of consecutive 16-bit 0 fields MUST be shortened
58                 stored_len = len;
59                 stored_field = field;
60         }
61         if (stored_len <= 1) {
62                 // The symbol "::" MUST NOT be used to shorten just one 16-bit 0 field.
63                 stored_len = 0;
64                 stored_field = -1;
65         }
66         for (int i = 0; i < 8; i++) {
67                 if (i == stored_field) {
68                         sprintf(ptr, ":");
69                         ptr++;
70                         if (i == 0) {
71                                 sprintf(ptr, ":");
72                                 ptr++;
73                         }
74                         i +=stored_len - 1;     // ++ done in for loop
75                         continue;
76                 }
77                 if ((int)a[i * 2] & 0xF0) {
78                         sprintf(ptr, "%02x%02x", (int)a[i * 2], (int)a[i * 2 + 1]);
79                         ptr+=4;
80                 } else if ((int)a[i * 2] & 0x0F) {
81                         sprintf(ptr, "%x%02x", (int)a[i * 2] >> 4, (int)a[i * 2] + 1);
82                         ptr+=3;
83                 } else if ((int)a[i * 2 + 1] & 0xF0) {
84                         sprintf(ptr, "%02x", (int)a[i * 2 + 1]);
85                         ptr+=2;
86                 } else {
87                         sprintf(ptr, "%x", ((int)a[i * 2 + 1]) & 0xF);
88                         ptr++;
89                 }
90                 if (i != 7) {
91                         sprintf(ptr, ":");
92                         ptr++;
93                 }
94         }
95         return ip6_str;
96 }
97
98 void set_link_local(struct ipv6_addr *ipv6_addr)
99 {
100         ipv6_addr->bytes[0] = 0xfe;
101         ipv6_addr->bytes[1] = 0x80;
102 }
103
104 // Create Extended Unique Identifier (RFC 2373)
105 // Store it in LSB of IPv6 address
106 void set_EUI(struct ipv6_addr *ipv6_addr, prox_rte_ether_addr *mac)
107 {
108         memcpy(&ipv6_addr->bytes[8], mac, 3);                                           // Copy first 3 bytes of MAC
109         ipv6_addr->bytes[8] = ipv6_addr->bytes[8] ^ 0x02;                               // Invert Universal/local bit
110         ipv6_addr->bytes[11] = 0xff;                                                    // Next 2 bytes are 0xfffe
111         ipv6_addr->bytes[12] = 0xfe;
112         memcpy(&ipv6_addr->bytes[13], &mac->addr_bytes[3], 3);                          // Copy last 3 bytes
113         // plog_info("mac = "MAC_BYTES_FMT", eui = "IPv6_BYTES_FMT"\n", MAC_BYTES(mac->addr_bytes), IPv6_BYTES(ipv6_addr->bytes));
114 }
115
116 void create_mac_from_EUI(struct ipv6_addr *ipv6_addr, prox_rte_ether_addr *mac)
117 {
118         memcpy(mac, &ipv6_addr->bytes[8], 3);
119         mac->addr_bytes[0] = mac->addr_bytes[0] ^ 0x02;
120         memcpy(&mac->addr_bytes[3], &ipv6_addr->bytes[13], 3);
121 }
122
123 static inline prox_rte_ipv6_hdr *prox_set_vlan_ipv6(prox_rte_ether_hdr *peth, uint16_t vlan)
124 {
125         prox_rte_ipv6_hdr *ipv6_hdr;
126
127         if (vlan) {
128                 prox_rte_vlan_hdr *vlan_hdr = (prox_rte_vlan_hdr *)(peth + 1);
129                 ipv6_hdr = (prox_rte_ipv6_hdr *)(vlan_hdr + 1);
130                 peth->ether_type = ETYPE_VLAN;
131                 vlan_hdr->eth_proto = ETYPE_IPv6;
132                 vlan_hdr->vlan_tci = rte_cpu_to_be_16(vlan);
133         } else {
134                 ipv6_hdr = (prox_rte_ipv6_hdr *)(peth + 1);
135                 peth->ether_type = ETYPE_IPv6;
136         }
137         return ipv6_hdr;
138 }
139
140 void build_router_advertisement(struct rte_mbuf *mbuf, prox_rte_ether_addr *s_addr, struct ipv6_addr *ipv6_s_addr, struct ipv6_addr *router_prefix, uint16_t vlan)
141 {
142         prox_rte_ether_hdr *peth = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
143         init_mbuf_seg(mbuf);
144         mbuf->ol_flags &= ~(RTE_MBUF_F_TX_IP_CKSUM|RTE_MBUF_F_TX_UDP_CKSUM);  // Software calculates the checksum
145
146         memcpy(peth->d_addr.addr_bytes, &prox_cfg.all_nodes_mac_addr, sizeof(prox_rte_ether_addr));
147         memcpy(peth->s_addr.addr_bytes, s_addr, sizeof(prox_rte_ether_addr));
148
149         prox_rte_ipv6_hdr *ipv6_hdr = prox_set_vlan_ipv6(peth, vlan);
150         ipv6_hdr->vtc_flow = 0x00000060;
151         ipv6_hdr->payload_len = rte_cpu_to_be_16(sizeof(struct icmpv6_RA) + sizeof(struct icmpv6_prefix_option));
152         ipv6_hdr->proto = ICMPv6;
153         ipv6_hdr->hop_limits = 255;
154         memcpy(ipv6_hdr->src_addr, ipv6_s_addr, sizeof(struct ipv6_addr));      // 0 = "Unspecified address" if unknown
155         memcpy(ipv6_hdr->dst_addr, &prox_cfg.all_nodes_ipv6_mcast_addr, sizeof(struct ipv6_addr));
156
157         struct icmpv6_RA *router_advertisement = (struct icmpv6_RA *)(ipv6_hdr + 1);
158         router_advertisement->type = ICMPv6_RA;
159         router_advertisement->code = 0;
160         router_advertisement->hop_limit = 255;
161         router_advertisement->bits = 0; // M and O bits set to 0 => no dhcpv6
162         router_advertisement->router_lifespan = rte_cpu_to_be_16(9000);         // 9000 sec
163         router_advertisement->reachable_timeout = rte_cpu_to_be_32(30000);      // 1 sec
164         router_advertisement->retrans_timeout = rte_cpu_to_be_32(1000);       // 30 sec
165
166         struct icmpv6_option *option = &router_advertisement->options;
167         option->type = ICMPv6_source_link_layer_address;
168         option->length = 1;     // 8 bytes
169         memcpy(&option->data, s_addr, sizeof(prox_rte_ether_addr));
170
171         struct icmpv6_prefix_option *prefix_option = (struct icmpv6_prefix_option *)(option + 1);
172         prefix_option->type = ICMPv6_prefix_information;
173         prefix_option->length = 4;              // 32 bytes
174         prefix_option->prefix_length = 64;      // 64 bits in prefix
175         prefix_option->flag = 0xc0;             // on-link flag & autonamous address-configuration flag are set
176         prefix_option->valid_lifetime = rte_cpu_to_be_32(86400);        // 1 day
177         prefix_option->preferred_lifetime = rte_cpu_to_be_32(43200);    // 12 hours
178         prefix_option->reserved = 0;
179         memcpy(&prefix_option->prefix, router_prefix, sizeof(struct ipv6_addr));
180         // Could Add MTU Option
181         router_advertisement->checksum = 0;
182         router_advertisement->checksum = rte_ipv6_udptcp_cksum(ipv6_hdr, router_advertisement);
183
184         uint16_t pktlen = rte_be_to_cpu_16(ipv6_hdr->payload_len) + sizeof(prox_rte_ipv6_hdr) + sizeof(prox_rte_ether_hdr);
185         rte_pktmbuf_pkt_len(mbuf) = pktlen + (vlan ? 4 : 0);
186         rte_pktmbuf_data_len(mbuf) = pktlen + (vlan ? 4 : 0);
187 }
188
189 void build_router_sollicitation(struct rte_mbuf *mbuf, prox_rte_ether_addr *s_addr, struct ipv6_addr *ipv6_s_addr, uint16_t vlan)
190 {
191         prox_rte_ether_hdr *peth = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
192
193         init_mbuf_seg(mbuf);
194         mbuf->ol_flags &= ~(RTE_MBUF_F_TX_IP_CKSUM|RTE_MBUF_F_TX_UDP_CKSUM);  // Software calculates the checksum
195
196         memcpy(peth->d_addr.addr_bytes, &prox_cfg.all_routers_mac_addr, sizeof(prox_rte_ether_addr));
197         memcpy(peth->s_addr.addr_bytes, s_addr, sizeof(prox_rte_ether_addr));
198
199         prox_rte_ipv6_hdr *ipv6_hdr = prox_set_vlan_ipv6(peth, vlan);
200         ipv6_hdr->vtc_flow = 0x00000060;
201         ipv6_hdr->payload_len = rte_cpu_to_be_16(sizeof(struct icmpv6_RS));
202         ipv6_hdr->proto = ICMPv6;
203         ipv6_hdr->hop_limits = 255;
204         memcpy(ipv6_hdr->src_addr, ipv6_s_addr, sizeof(struct ipv6_addr));      // 0 = "Unspecified address" if unknown
205         memcpy(ipv6_hdr->dst_addr, &prox_cfg.all_routers_ipv6_mcast_addr, sizeof(struct ipv6_addr));
206
207         struct icmpv6_RS *router_sollicitation = (struct icmpv6_RS *)(ipv6_hdr + 1);
208         router_sollicitation->type = ICMPv6_RS;
209         router_sollicitation->code = 0;
210         router_sollicitation->options.type = ICMPv6_source_link_layer_address;
211         router_sollicitation->options.length = 1;       // 8 bytes
212         memcpy(&router_sollicitation->options.data, s_addr, sizeof(prox_rte_ether_addr));
213
214         router_sollicitation->checksum = 0;
215         router_sollicitation->checksum = rte_ipv6_udptcp_cksum(ipv6_hdr, router_sollicitation);
216         uint16_t pktlen = rte_be_to_cpu_16(ipv6_hdr->payload_len) + sizeof(prox_rte_ipv6_hdr) + sizeof(prox_rte_ether_hdr);
217         rte_pktmbuf_pkt_len(mbuf) = pktlen + (vlan ? 4 : 0);
218         rte_pktmbuf_data_len(mbuf) = pktlen + (vlan ? 4 : 0);
219 }
220
221 void build_neighbour_sollicitation(struct rte_mbuf *mbuf, prox_rte_ether_addr *s_addr, struct ipv6_addr *dst, struct ipv6_addr *src, uint16_t vlan)
222 {
223         prox_rte_ether_hdr *peth = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
224         prox_rte_ether_addr mac_dst;
225         set_mcast_mac_from_ipv6(&mac_dst, dst);
226
227         init_mbuf_seg(mbuf);
228         mbuf->ol_flags &= ~(RTE_MBUF_F_TX_IP_CKSUM|RTE_MBUF_F_TX_UDP_CKSUM);  // Software calculates the checksum
229
230         memcpy(peth->d_addr.addr_bytes, &mac_dst, sizeof(prox_rte_ether_addr));
231         memcpy(peth->s_addr.addr_bytes, s_addr, sizeof(prox_rte_ether_addr));
232
233         prox_rte_ipv6_hdr *ipv6_hdr = prox_set_vlan_ipv6(peth, vlan);
234
235         ipv6_hdr->vtc_flow = 0x00000060;
236         ipv6_hdr->payload_len = rte_cpu_to_be_16(sizeof(struct icmpv6_NS));
237         ipv6_hdr->proto = ICMPv6;
238         ipv6_hdr->hop_limits = 255;
239         memcpy(ipv6_hdr->src_addr, src, 16);
240         memcpy(ipv6_hdr->dst_addr, dst, 16);
241
242         struct icmpv6_NS *neighbour_sollicitation = (struct icmpv6_NS *)(ipv6_hdr + 1);
243         neighbour_sollicitation->type = ICMPv6_NS;
244         neighbour_sollicitation->code = 0;
245         neighbour_sollicitation->reserved = 0;
246         memcpy(&neighbour_sollicitation->target_address, dst, sizeof(struct ipv6_addr));
247         neighbour_sollicitation->options.type = ICMPv6_source_link_layer_address;
248         neighbour_sollicitation->options.length = 1;    // 8 bytes
249         memcpy(&neighbour_sollicitation->options.data, s_addr, sizeof(prox_rte_ether_addr));
250         neighbour_sollicitation->checksum = 0;
251         neighbour_sollicitation->checksum = rte_ipv6_udptcp_cksum(ipv6_hdr, neighbour_sollicitation);
252
253         uint16_t pktlen = rte_be_to_cpu_16(ipv6_hdr->payload_len) + sizeof(prox_rte_ipv6_hdr) + sizeof(prox_rte_ether_hdr);
254         rte_pktmbuf_pkt_len(mbuf) = pktlen + (vlan ? 4 : 0);
255         rte_pktmbuf_data_len(mbuf) = pktlen + (vlan ? 4 : 0);
256 }
257
258 void build_neighbour_advertisement(struct task_base *tbase, struct rte_mbuf *mbuf, prox_rte_ether_addr *target, struct ipv6_addr *src_ipv6_addr, int sollicited, uint16_t vlan)
259 {
260         struct task_master *task = (struct task_master *)tbase;
261         prox_rte_ether_hdr *peth = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
262
263         uint8_t port_id = get_port(mbuf);
264
265         init_mbuf_seg(mbuf);
266         mbuf->ol_flags &= ~(RTE_MBUF_F_TX_IP_CKSUM|RTE_MBUF_F_TX_UDP_CKSUM);  // Software calculates the checksum
267
268         prox_rte_ipv6_hdr *ipv6_hdr = prox_set_vlan_ipv6(peth, vlan);
269
270         // If source mac is null, use all_nodes_mac_addr.
271         if ((!sollicited) || (memcmp(peth->s_addr.addr_bytes, &null_addr, sizeof(struct ipv6_addr)) == 0)) {
272                 memcpy(peth->d_addr.addr_bytes, &prox_cfg.all_nodes_mac_addr, sizeof(prox_rte_ether_addr));
273                 memcpy(ipv6_hdr->dst_addr, &prox_cfg.all_nodes_ipv6_mcast_addr, sizeof(struct ipv6_addr));
274         } else {
275                 memcpy(peth->d_addr.addr_bytes, peth->s_addr.addr_bytes, sizeof(prox_rte_ether_addr));
276                 memcpy(ipv6_hdr->dst_addr, ipv6_hdr->src_addr, sizeof(struct ipv6_addr));
277         }
278
279         memcpy(peth->s_addr.addr_bytes, &task->internal_port_table[port_id].mac, sizeof(prox_rte_ether_addr));
280
281         ipv6_hdr->vtc_flow = 0x00000060;
282         ipv6_hdr->payload_len = rte_cpu_to_be_16(sizeof(struct icmpv6_NA));
283         ipv6_hdr->proto = ICMPv6;
284         ipv6_hdr->hop_limits = 255;
285         memcpy(ipv6_hdr->src_addr, src_ipv6_addr, sizeof(struct ipv6_addr));
286
287         struct icmpv6_NA *neighbour_advertisement = (struct icmpv6_NA *)(ipv6_hdr + 1);
288         neighbour_advertisement->type = ICMPv6_NA;
289         neighbour_advertisement->code = 0;
290         neighbour_advertisement->reserved = 0;
291         if (task->internal_port_table[port_id].flags & IPV6_ROUTER)
292                 neighbour_advertisement->bits = 0xC0; // R+S bit set
293         else
294                 neighbour_advertisement->bits = 0x40; // S bit set
295         if (!sollicited) {
296                 memcpy(&neighbour_advertisement->destination_address, src_ipv6_addr, sizeof(struct ipv6_addr));
297                 neighbour_advertisement->bits &= 0xBF; // Clear S bit
298                 neighbour_advertisement->bits |= 0x20; // Overide bit
299         }
300         // else neighbour_advertisement->destination_address is already set to neighbour_sollicitation->target_address
301
302         struct icmpv6_option *option = &neighbour_advertisement->options;
303         // Do not think this is necessary
304         // option->type = ICMPv6_source_link_layer_address;
305         // option->length = 1;  // 8 bytes
306         // memcpy(&option->data, &task->internal_port_table[port_id].mac, sizeof(prox_rte_ether_addr));
307
308         // option = option + 1;
309         option->type = ICMPv6_target_link_layer_address;
310         option->length = 1;     // 8 bytes
311         memcpy(&option->data, target, sizeof(prox_rte_ether_addr));
312
313         neighbour_advertisement->checksum = 0;
314         neighbour_advertisement->checksum = rte_ipv6_udptcp_cksum(ipv6_hdr, neighbour_advertisement);
315         uint16_t pktlen = rte_be_to_cpu_16(ipv6_hdr->payload_len) + sizeof(prox_rte_ipv6_hdr) + sizeof(prox_rte_ether_hdr);
316         rte_pktmbuf_pkt_len(mbuf) = pktlen + (vlan ? 4 : 0);
317         rte_pktmbuf_data_len(mbuf) = pktlen + (vlan ? 4 : 0);
318 }
319
320 prox_rte_ipv6_hdr *prox_get_ipv6_hdr(prox_rte_ether_hdr *hdr, uint16_t len, uint16_t *vlan)
321 {
322         prox_rte_vlan_hdr *vlan_hdr;
323         prox_rte_ipv6_hdr *ipv6_hdr;
324         uint16_t ether_type = hdr->ether_type;
325         uint16_t l2_len = sizeof(prox_rte_ether_hdr);
326         ipv6_hdr = (prox_rte_ipv6_hdr *)(hdr + 1);
327
328         while (((ether_type == ETYPE_8021ad) || (ether_type == ETYPE_VLAN)) && (l2_len + sizeof(prox_rte_vlan_hdr) < len)) {
329                 vlan_hdr = (prox_rte_vlan_hdr *)((uint8_t *)hdr + l2_len);
330                 l2_len +=4;
331                 ether_type = vlan_hdr->eth_proto;
332                 *vlan = rte_be_to_cpu_16(vlan_hdr->vlan_tci & 0xFF0F);
333                 ipv6_hdr = (prox_rte_ipv6_hdr *)(vlan_hdr + 1);
334         }
335         if (ether_type == ETYPE_IPv6)
336                 return ipv6_hdr;
337         else
338                 return NULL;
339 }