2 // Copyright (c) 2020 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "task_base.h"
18 #include "handle_master.h"
20 #include "prox_ipv6.h"
22 struct ipv6_addr null_addr = {{0}};
23 char ip6_str[40]; // 8 blocks of 2 bytes (4 char) + 1x ":" between blocks
25 void set_mcast_mac_from_ipv6(prox_rte_ether_addr *mac, struct ipv6_addr *ipv6_addr)
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));
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)
36 uint8_t *a = (uint8_t *)addr;
38 int field = -1, len = 0, stored_field = 0, stored_len = 0;
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)) {
45 field = i; // Store where the first 0 field started
47 if (len > stored_len) {
48 // the longest run of consecutive 16-bit 0 fields MUST be shortened
56 if (len > stored_len) {
57 // the longest run of consecutive 16-bit 0 fields MUST be shortened
61 if (stored_len <= 1) {
62 // The symbol "::" MUST NOT be used to shorten just one 16-bit 0 field.
66 for (int i = 0; i < 8; i++) {
67 if (i == stored_field) {
74 i +=stored_len - 1; // ++ done in for loop
77 if ((int)a[i * 2] & 0xF0) {
78 sprintf(ptr, "%02x%02x", (int)a[i * 2], (int)a[i * 2 + 1]);
80 } else if ((int)a[i * 2] & 0x0F) {
81 sprintf(ptr, "%x%02x", (int)a[i * 2] >> 4, (int)a[i * 2] + 1);
83 } else if ((int)a[i * 2 + 1] & 0xF0) {
84 sprintf(ptr, "%02x", (int)a[i * 2 + 1]);
87 sprintf(ptr, "%x", ((int)a[i * 2 + 1]) & 0xF);
98 void set_link_local(struct ipv6_addr *ipv6_addr)
100 ipv6_addr->bytes[0] = 0xfe;
101 ipv6_addr->bytes[1] = 0x80;
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)
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));
116 void create_mac_from_EUI(struct ipv6_addr *ipv6_addr, prox_rte_ether_addr *mac)
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);
122 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)
124 prox_rte_ether_hdr *peth = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
126 mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM); // Software calculates the checksum
128 memcpy(peth->d_addr.addr_bytes, &prox_cfg.all_nodes_mac_addr, sizeof(prox_rte_ether_addr));
129 memcpy(peth->s_addr.addr_bytes, s_addr, sizeof(prox_rte_ether_addr));
130 peth->ether_type = ETYPE_IPv6;
132 prox_rte_ipv6_hdr *ipv6_hdr = (prox_rte_ipv6_hdr *)(peth + 1);
133 ipv6_hdr->vtc_flow = 0x00000060;
134 ipv6_hdr->payload_len = rte_cpu_to_be_16(sizeof(struct icmpv6_RA) + sizeof(struct icmpv6_prefix_option));
135 ipv6_hdr->proto = ICMPv6;
136 ipv6_hdr->hop_limits = 255;
137 memcpy(ipv6_hdr->src_addr, ipv6_s_addr, sizeof(struct ipv6_addr)); // 0 = "Unspecified address" if unknown
138 memcpy(ipv6_hdr->dst_addr, &prox_cfg.all_nodes_ipv6_mcast_addr, sizeof(struct ipv6_addr));
140 struct icmpv6_RA *router_advertisement = (struct icmpv6_RA *)(ipv6_hdr + 1);
141 router_advertisement->type = ICMPv6_RA;
142 router_advertisement->code = 0;
143 router_advertisement->hop_limit = 255;
144 router_advertisement->bits = 0; // M and O bits set to 0 => no dhcpv6
145 router_advertisement->router_lifespan = rte_cpu_to_be_16(9000); // 9000 sec
146 router_advertisement->reachable_timeout = rte_cpu_to_be_32(30000); // 1 sec
147 router_advertisement->retrans_timeout = rte_cpu_to_be_32(1000); // 30 sec
149 struct icmpv6_option *option = &router_advertisement->options;
150 option->type = ICMPv6_source_link_layer_address;
151 option->length = 1; // 8 bytes
152 memcpy(&option->data, s_addr, sizeof(prox_rte_ether_addr));
154 struct icmpv6_prefix_option *prefix_option = (struct icmpv6_prefix_option *)(option + 1);
155 prefix_option->type = ICMPv6_prefix_information;
156 prefix_option->length = 4; // 32 bytes
157 prefix_option->prefix_length = 64; // 64 bits in prefix
158 prefix_option->flag = 0xc0; // on-link flag & autonamous address-configuration flag are set
159 prefix_option->valid_lifetime = rte_cpu_to_be_32(86400); // 1 day
160 prefix_option->preferred_lifetime = rte_cpu_to_be_32(43200); // 12 hours
161 prefix_option->reserved = 0;
162 memcpy(&prefix_option->prefix, router_prefix, sizeof(struct ipv6_addr));
163 // Could Add MTU Option
164 router_advertisement->checksum = 0;
165 router_advertisement->checksum = rte_ipv6_udptcp_cksum(ipv6_hdr, router_advertisement);
167 uint16_t pktlen = rte_be_to_cpu_16(ipv6_hdr->payload_len) + sizeof(prox_rte_ipv6_hdr) + sizeof(prox_rte_ether_hdr);
168 rte_pktmbuf_pkt_len(mbuf) = pktlen;
169 rte_pktmbuf_data_len(mbuf) = pktlen;
172 void build_router_sollicitation(struct rte_mbuf *mbuf, prox_rte_ether_addr *s_addr, struct ipv6_addr *ipv6_s_addr)
174 prox_rte_ether_hdr *peth = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
177 mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM); // Software calculates the checksum
179 memcpy(peth->d_addr.addr_bytes, &prox_cfg.all_routers_mac_addr, sizeof(prox_rte_ether_addr));
180 memcpy(peth->s_addr.addr_bytes, s_addr, sizeof(prox_rte_ether_addr));
181 peth->ether_type = ETYPE_IPv6;
183 prox_rte_ipv6_hdr *ipv6_hdr = (prox_rte_ipv6_hdr *)(peth + 1);
184 ipv6_hdr->vtc_flow = 0x00000060;
185 ipv6_hdr->payload_len = rte_cpu_to_be_16(sizeof(struct icmpv6_RS));
186 ipv6_hdr->proto = ICMPv6;
187 ipv6_hdr->hop_limits = 255;
188 memcpy(ipv6_hdr->src_addr, ipv6_s_addr, sizeof(struct ipv6_addr)); // 0 = "Unspecified address" if unknown
189 memcpy(ipv6_hdr->dst_addr, &prox_cfg.all_routers_ipv6_mcast_addr, sizeof(struct ipv6_addr));
191 struct icmpv6_RS *router_sollicitation = (struct icmpv6_RS *)(ipv6_hdr + 1);
192 router_sollicitation->type = ICMPv6_RS;
193 router_sollicitation->code = 0;
194 router_sollicitation->options.type = ICMPv6_source_link_layer_address;
195 router_sollicitation->options.length = 1; // 8 bytes
196 memcpy(&router_sollicitation->options.data, s_addr, sizeof(prox_rte_ether_addr));
198 router_sollicitation->checksum = 0;
199 router_sollicitation->checksum = rte_ipv6_udptcp_cksum(ipv6_hdr, router_sollicitation);
200 uint16_t pktlen = rte_be_to_cpu_16(ipv6_hdr->payload_len) + sizeof(prox_rte_ipv6_hdr) + sizeof(prox_rte_ether_hdr);
201 rte_pktmbuf_pkt_len(mbuf) = pktlen;
202 rte_pktmbuf_data_len(mbuf) = pktlen;
205 void build_neighbour_sollicitation(struct rte_mbuf *mbuf, prox_rte_ether_addr *s_addr, struct ipv6_addr *dst, struct ipv6_addr *src)
207 prox_rte_ether_hdr *peth = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
208 prox_rte_ether_addr mac_dst;
209 set_mcast_mac_from_ipv6(&mac_dst, dst);
212 mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM); // Software calculates the checksum
214 memcpy(peth->d_addr.addr_bytes, &mac_dst, sizeof(prox_rte_ether_addr));
215 memcpy(peth->s_addr.addr_bytes, s_addr, sizeof(prox_rte_ether_addr));
216 peth->ether_type = ETYPE_IPv6;
218 prox_rte_ipv6_hdr *ipv6_hdr = (prox_rte_ipv6_hdr *)(peth + 1);
219 ipv6_hdr->vtc_flow = 0x00000060;
220 ipv6_hdr->payload_len = rte_cpu_to_be_16(sizeof(struct icmpv6_NS));
221 ipv6_hdr->proto = ICMPv6;
222 ipv6_hdr->hop_limits = 255;
223 memcpy(ipv6_hdr->src_addr, src, 16);
224 memcpy(ipv6_hdr->dst_addr, dst, 16);
226 struct icmpv6_NS *neighbour_sollicitation = (struct icmpv6_NS *)(ipv6_hdr + 1);
227 neighbour_sollicitation->type = ICMPv6_NS;
228 neighbour_sollicitation->code = 0;
229 neighbour_sollicitation->reserved = 0;
230 memcpy(&neighbour_sollicitation->target_address, dst, sizeof(struct ipv6_addr));
231 neighbour_sollicitation->options.type = ICMPv6_source_link_layer_address;
232 neighbour_sollicitation->options.length = 1; // 8 bytes
233 memcpy(&neighbour_sollicitation->options.data, s_addr, sizeof(prox_rte_ether_addr));
234 neighbour_sollicitation->checksum = 0;
235 neighbour_sollicitation->checksum = rte_ipv6_udptcp_cksum(ipv6_hdr, neighbour_sollicitation);
237 uint16_t pktlen = rte_be_to_cpu_16(ipv6_hdr->payload_len) + sizeof(prox_rte_ipv6_hdr) + sizeof(prox_rte_ether_hdr);
238 rte_pktmbuf_pkt_len(mbuf) = pktlen;
239 rte_pktmbuf_data_len(mbuf) = pktlen;
242 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)
244 struct task_master *task = (struct task_master *)tbase;
245 prox_rte_ether_hdr *peth = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
246 prox_rte_ipv6_hdr *ipv6_hdr = (prox_rte_ipv6_hdr *)(peth + 1);
248 uint8_t port_id = get_port(mbuf);
251 mbuf->ol_flags &= ~(PKT_TX_IP_CKSUM|PKT_TX_UDP_CKSUM); // Software calculates the checksum
253 // If source mac is null, use all_nodes_mac_addr.
254 if ((!sollicited) || (memcmp(peth->s_addr.addr_bytes, &null_addr, sizeof(struct ipv6_addr)) == 0)) {
255 memcpy(peth->d_addr.addr_bytes, &prox_cfg.all_nodes_mac_addr, sizeof(prox_rte_ether_addr));
256 memcpy(ipv6_hdr->dst_addr, &prox_cfg.all_nodes_ipv6_mcast_addr, sizeof(struct ipv6_addr));
258 memcpy(peth->d_addr.addr_bytes, peth->s_addr.addr_bytes, sizeof(prox_rte_ether_addr));
259 memcpy(ipv6_hdr->dst_addr, ipv6_hdr->src_addr, sizeof(struct ipv6_addr));
262 memcpy(peth->s_addr.addr_bytes, &task->internal_port_table[port_id].mac, sizeof(prox_rte_ether_addr));
263 peth->ether_type = ETYPE_IPv6;
265 ipv6_hdr->vtc_flow = 0x00000060;
266 ipv6_hdr->payload_len = rte_cpu_to_be_16(sizeof(struct icmpv6_NA));
267 ipv6_hdr->proto = ICMPv6;
268 ipv6_hdr->hop_limits = 255;
269 memcpy(ipv6_hdr->src_addr, src_ipv6_addr, sizeof(struct ipv6_addr));
271 struct icmpv6_NA *neighbour_advertisement = (struct icmpv6_NA *)(ipv6_hdr + 1);
272 neighbour_advertisement->type = ICMPv6_NA;
273 neighbour_advertisement->code = 0;
274 neighbour_advertisement->reserved = 0;
275 if (task->internal_port_table[port_id].flags & IPV6_ROUTER)
276 neighbour_advertisement->bits = 0xC0; // R+S bit set
278 neighbour_advertisement->bits = 0x40; // S bit set
280 memcpy(&neighbour_advertisement->destination_address, src_ipv6_addr, sizeof(struct ipv6_addr));
281 neighbour_advertisement->bits &= 0xBF; // Clear S bit
282 neighbour_advertisement->bits |= 0x20; // Overide bit
284 // else neighbour_advertisement->destination_address is already set to neighbour_sollicitation->target_address
286 struct icmpv6_option *option = &neighbour_advertisement->options;
287 // Do not think this is necessary
288 // option->type = ICMPv6_source_link_layer_address;
289 // option->length = 1; // 8 bytes
290 // memcpy(&option->data, &task->internal_port_table[port_id].mac, sizeof(prox_rte_ether_addr));
292 // option = option + 1;
293 option->type = ICMPv6_target_link_layer_address;
294 option->length = 1; // 8 bytes
295 memcpy(&option->data, target, sizeof(prox_rte_ether_addr));
297 neighbour_advertisement->checksum = 0;
298 neighbour_advertisement->checksum = rte_ipv6_udptcp_cksum(ipv6_hdr, neighbour_advertisement);
299 uint16_t pktlen = rte_be_to_cpu_16(ipv6_hdr->payload_len) + sizeof(prox_rte_ipv6_hdr) + sizeof(prox_rte_ether_hdr);
300 rte_pktmbuf_pkt_len(mbuf) = pktlen;
301 rte_pktmbuf_data_len(mbuf) = pktlen;