CNDP  22.08.0
cne_ether.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2019-2022 Intel Corporation
3  */
4 
5 #ifndef _CNE_ETHER_H_
6 #define _CNE_ETHER_H_
7 
8 #include <errno.h> // for errno
9 #include <stdio.h> // for NULL, snprintf
10 #include <stdint.h> // for uint8_t, uint16_t, UINT16_MAX, UINT8_MAX
11 #include <stdlib.h> // for strtoul
12 #include <net/ethernet.h> // for ether_addr, ETHER_MAX_LEN
13 #include <linux/if_ether.h> // for ETH_ALEN
14 #include <stdbool.h>
15 #include <string.h>
16 
17 #include <cne_common.h>
18 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 #define CNE_ETHER_MAX_VLAN_FRAME_LEN (ETHER_MAX_LEN + 4)
32 #define CNE_ETHER_MAX_JUMBO_FRAME_LEN 0x3F00
34 #define CNE_ETHER_MAX_VLAN_ID 4095
36 #define CNE_ETHER_MIN_MTU 68
38 #ifndef ETH_ALEN
39 #define ETH_ALEN 6
40 
52 struct ether_addr {
53  uint8_t ether_addr_octet[ETH_ALEN];
54 } __cne_packed;
55 #endif
56 
57 #define ETHER_LOCAL_ADMIN_ADDR 0x02
58 #define ETHER_GROUP_ADDR 0x01
64 struct cne_ether_hdr {
65  struct ether_addr d_addr;
66  struct ether_addr s_addr;
67  uint16_t ether_type;
68 } __cne_aligned(2);
69 
75 struct cne_vlan_hdr {
76  uint16_t vlan_tci;
77  uint16_t eth_proto;
78 } __cne_packed;
79 
80 /* Ethernet frame types */
81 #define CNE_ETHER_TYPE_IPV4 0x0800
82 #define CNE_ETHER_TYPE_IPV6 0x86DD
83 #define CNE_ETHER_TYPE_ARP 0x0806
84 #define CNE_ETHER_TYPE_RARP 0x8035
85 #define CNE_ETHER_TYPE_VLAN 0x8100
86 #define CNE_ETHER_TYPE_QINQ 0x88A8
87 #define CNE_ETHER_TYPE_PPPOE_DISCOVERY 0x8863
88 #define CNE_ETHER_TYPE_PPPOE_SESSION 0x8864
89 #define CNE_ETHER_TYPE_ETAG 0x893F
90 #define CNE_ETHER_TYPE_1588 0x88F7
92 #define CNE_ETHER_TYPE_SLOW 0x8809
93 #define CNE_ETHER_TYPE_TEB 0x6558
94 #define CNE_ETHER_TYPE_LLDP 0x88CC
95 #define CNE_ETHER_TYPE_MPLS 0x8847
96 #define CNE_ETHER_TYPE_MPLSM 0x8848
98 /* Ethernet frame types */
99 #define __ETHER_TYPE_IPV4 0x0008
100 #define __ETHER_TYPE_IPV6 0xDD86
101 #define __ETHER_TYPE_ARP 0x0608
102 #define __ETHER_TYPE_RARP 0x3580
103 #define __ETHER_TYPE_VLAN 0x0081
104 #define __ETHER_TYPE_QINQ 0xA888
105 #define __ETHER_TYPE_PPPOE_DISCOVERY 0x6388
106 #define __ETHER_TYPE_PPPOE_SESSION 0x6488
107 #define __ETHER_TYPE_ETAG 0x3F89
108 #define __ETHER_TYPE_1588 0xF788
110 #define __ETHER_TYPE_SLOW 0x0988
111 #define __ETHER_TYPE_TEB 0x5865
112 #define __ETHER_TYPE_LLDP 0xCC88
113 #define __ETHER_TYPE_MPLS 0x4788
114 #define __ETHER_TYPE_MPLSM 0x4888
130 CNDP_API __cne_always_inline int
131 ether_addr_is_same(const struct ether_addr *ea1, const struct ether_addr *ea2)
132 {
133  const uint16_t *w1 = (const uint16_t *)ea1;
134  const uint16_t *w2 = (const uint16_t *)ea2;
135 
136  return ((w1[0] ^ w2[0]) | (w1[1] ^ w2[1]) | (w1[2] ^ w2[2])) == 0;
137 }
138 
149 CNDP_API __cne_always_inline int
151 {
152  const uint16_t *w = (const uint16_t *)ea;
153 
154  return (w[0] | w[1] | w[2]) == 0;
155 }
156 
167 CNDP_API __cne_always_inline int
169 {
170  return (ea->ether_addr_octet[0] & ETHER_GROUP_ADDR) == 0;
171 }
172 
183 CNDP_API __cne_always_inline int
185 {
186  return ea->ether_addr_octet[0] & ETHER_GROUP_ADDR;
187 }
188 
199 CNDP_API __cne_always_inline int
201 {
202  const uint16_t *ea_words = (const uint16_t *)ea;
203 
204  return (ea_words[0] == 0xFFFF && ea_words[1] == 0xFFFF && ea_words[2] == 0xFFFF);
205 }
206 
217 CNDP_API __cne_always_inline int
219 {
220  return (ea->ether_addr_octet[0] & ETHER_LOCAL_ADMIN_ADDR) == 0;
221 }
222 
233 CNDP_API __cne_always_inline int
235 {
236  return (ea->ether_addr_octet[0] & ETHER_LOCAL_ADMIN_ADDR) != 0;
237 }
238 
250 CNDP_API __cne_always_inline int
252 {
253  return ether_addr_is_unicast(ea) && (!ether_addr_is_zero(ea));
254 }
255 
262 CNDP_API __cne_always_inline void
263 ether_random_addr(uint8_t *addr)
264 {
265  uint64_t rnd = rand();
266  uint8_t *p = (uint8_t *)&rnd;
267 
268  memcpy(addr, p, ETH_ALEN);
269  addr[0] &= (uint8_t)~ETHER_GROUP_ADDR; /* clear multicast bit */
270  addr[0] |= ETHER_LOCAL_ADMIN_ADDR; /* set local assignment bit */
271 }
272 
281 CNDP_API __cne_always_inline void
282 ether_addr_copy(const struct ether_addr *ea_from, struct ether_addr *ea_to)
283 {
284 #ifdef __INTEL_COMPILER
285  uint16_t *from_words = (uint16_t *)(ea_from->ether_addr_octet);
286  uint16_t *to_words = (uint16_t *)(ea_to->ether_addr_octet);
287 
288  to_words[0] = from_words[0];
289  to_words[1] = from_words[1];
290  to_words[2] = from_words[2];
291 #else
292  /*
293  * Use the common way, because of a strange gcc warning.
294  */
295  *ea_to = *ea_from;
296 #endif
297 }
298 
299 /* Swap two 16 bit values */
300 CNDP_API __cne_always_inline void
301 ether_swap(uint16_t *t, uint16_t *f)
302 {
303  uint16_t v;
304 
305  v = *t;
306  *t = *f;
307  *f = v;
308 }
309 
310 /* Swap two ethernet addresses */
311 CNDP_API __cne_always_inline void
312 ether_addr_swap(struct ether_addr *t, struct ether_addr *f)
313 {
314  uint16_t *d = (uint16_t *)t;
315  uint16_t *s = (uint16_t *)f;
316 
317  ether_swap(d++, s++);
318  ether_swap(d++, s++);
319  ether_swap(d, s);
320 }
321 
322 #define CNE_ETHER_ADDR_FMT_SIZE 18
333 CNDP_API __cne_always_inline void
334 ether_format_addr(char *buf, uint16_t size, const struct ether_addr *eth_addr)
335 {
336  // clang-format off
337  snprintf(buf, size, "%02X:%02X:%02X:%02X:%02X:%02X", eth_addr->ether_addr_octet[0],
338  eth_addr->ether_addr_octet[1], eth_addr->ether_addr_octet[2],
339  eth_addr->ether_addr_octet[3], eth_addr->ether_addr_octet[4],
340  eth_addr->ether_addr_octet[5]);
341  // clang-format on
342 }
343 
344 CNDP_API __cne_always_inline int8_t
345 __get_xdigit(char ch)
346 {
347  if (ch >= '0' && ch <= '9')
348  return ch - '0';
349  if (ch >= 'a' && ch <= 'f')
350  return ch - 'a' + 10;
351  if (ch >= 'A' && ch <= 'F')
352  return ch - 'A' + 10;
353  return -1;
354 }
355 
356 /* Convert 00:11:22:33:44:55 to ethernet address */
357 CNDP_API __cne_always_inline bool
358 __get_ether_addr6(const char *s0, struct ether_addr *ea)
359 {
360  const char *s = s0;
361  int i;
362 
363  for (i = 0; i < ETH_ALEN; i++) {
364  int8_t x;
365 
366  x = __get_xdigit(*s++);
367  if (x < 0)
368  return false;
369 
370  ea->ether_addr_octet[i] = x << 4;
371  x = __get_xdigit(*s++);
372  if (x < 0)
373  return false;
374  ea->ether_addr_octet[i] |= x;
375 
376  if (i < ETH_ALEN - 1 && *s++ != ':')
377  return false;
378  }
379 
380  /* return true if at end of string */
381  return *s == '\0';
382 }
383 
384 /* Convert 0011:2233:4455 to ethernet address */
385 CNDP_API __cne_always_inline bool
386 __get_ether_addr3(const char *s, struct ether_addr *ea)
387 {
388  int i, j;
389 
390  for (i = 0; i < ETH_ALEN; i += 2) {
391  uint16_t w = 0;
392 
393  for (j = 0; j < 4; j++) {
394  int8_t x;
395 
396  x = __get_xdigit(*s++);
397  if (x < 0)
398  return false;
399  w = (w << 4) | x;
400  }
401  ea->ether_addr_octet[i] = w >> 8;
402  ea->ether_addr_octet[i + 1] = w & 0xff;
403 
404  if (i < ETH_ALEN - 2 && *s++ != ':')
405  return false;
406  }
407 
408  return *s == '\0';
409 }
410 
425 CNDP_API __cne_always_inline int
426 ether_unformat_addr(const char *s, struct ether_addr *ea)
427 {
428  if (__get_ether_addr6(s, ea))
429  return 0;
430  if (__get_ether_addr3(s, ea))
431  return 0;
432 
433  errno = EINVAL;
434  return -1;
435 }
436 
448 CNDP_API __cne_always_inline struct ether_addr *
449 cne_ether_aton(const char *a, struct ether_addr *e)
450 {
451  int i;
452  char *end;
453  unsigned long o[ETH_ALEN];
454 
455  if (!e)
456  return NULL;
457 
458  i = 0;
459  do {
460  errno = 0;
461  o[i] = strtoul(a, &end, 16);
462  if (errno != 0 || end == a || (end[0] != ':' && end[0] != 0))
463  return NULL;
464  a = end + 1;
465  } while (++i != sizeof(o) / sizeof(o[0]) && end[0] != 0);
466 
467  /* Junk at the end of line */
468  if (end[0] != 0)
469  return NULL;
470 
471  /* Support the format XX:XX:XX:XX:XX:XX */
472  if (i == ETH_ALEN) {
473  while (i-- != 0) {
474  if (o[i] > UINT8_MAX)
475  return NULL;
476  e->ether_addr_octet[i] = (uint8_t)o[i];
477  }
478  /* Support the format XXXX:XXXX:XXXX */
479  } else if (i == ETH_ALEN / 2) {
480  while (i-- != 0) {
481  if (o[i] > UINT16_MAX)
482  return NULL;
483  e->ether_addr_octet[i * 2] = (uint8_t)(o[i] >> 8);
484  e->ether_addr_octet[i * 2 + 1] = (uint8_t)(o[i] & 0xff);
485  }
486  /* unknown format */
487  } else
488  return NULL;
489 
490  return e;
491 }
492 
493 /* Convert MAC address to ascii */
494 CNDP_API __cne_always_inline char *
495 inet_mtoa(char *buff, int len, struct ether_addr *eaddr)
496 {
497  snprintf(buff, len, "%02x:%02x:%02x:%02x:%02x:%02x", eaddr->ether_addr_octet[0],
498  eaddr->ether_addr_octet[1], eaddr->ether_addr_octet[2], eaddr->ether_addr_octet[3],
499  eaddr->ether_addr_octet[4], eaddr->ether_addr_octet[5]);
500  return buff;
501 }
502 
503 #ifdef __cplusplus
504 }
505 #endif
506 
507 #endif /* _CNE_ETHER_H_ */
#define __cne_packed
Definition: cne_common.h:129
#define __cne_aligned(a)
Definition: cne_common.h:124
#define __cne_always_inline
Definition: cne_common.h:218
CNDP_API __cne_always_inline void ether_random_addr(uint8_t *addr)
Definition: cne_ether.h:263
CNDP_API __cne_always_inline int ether_addr_is_zero(const struct ether_addr *ea)
Definition: cne_ether.h:150
CNDP_API __cne_always_inline int ether_addr_is_unicast(const struct ether_addr *ea)
Definition: cne_ether.h:168
CNDP_API __cne_always_inline int ether_addr_is_broadcast(const struct ether_addr *ea)
Definition: cne_ether.h:200
CNDP_API __cne_always_inline int ether_addr_is_universal(const struct ether_addr *ea)
Definition: cne_ether.h:218
#define ETHER_GROUP_ADDR
Definition: cne_ether.h:58
CNDP_API __cne_always_inline int ether_addr_is_valid_assigned(const struct ether_addr *ea)
Definition: cne_ether.h:251
CNDP_API __cne_always_inline int ether_addr_is_same(const struct ether_addr *ea1, const struct ether_addr *ea2)
Definition: cne_ether.h:131
#define ETHER_LOCAL_ADMIN_ADDR
Definition: cne_ether.h:57
CNDP_API __cne_always_inline void ether_format_addr(char *buf, uint16_t size, const struct ether_addr *eth_addr)
Definition: cne_ether.h:334
CNDP_API __cne_always_inline int ether_addr_is_local_admin(const struct ether_addr *ea)
Definition: cne_ether.h:234
CNDP_API __cne_always_inline void ether_addr_copy(const struct ether_addr *ea_from, struct ether_addr *ea_to)
Definition: cne_ether.h:282
CNDP_API __cne_always_inline int ether_addr_is_multicast(const struct ether_addr *ea)
Definition: cne_ether.h:184
CNDP_API __cne_always_inline int ether_unformat_addr(const char *s, struct ether_addr *ea)
Definition: cne_ether.h:426
CNDP_API __cne_always_inline struct ether_addr * cne_ether_aton(const char *a, struct ether_addr *e)
Definition: cne_ether.h:449
struct ether_addr s_addr
Definition: cne_ether.h:66
struct ether_addr d_addr
Definition: cne_ether.h:65
uint16_t ether_type
Definition: cne_ether.h:67
uint16_t vlan_tci
Definition: cne_ether.h:76
uint16_t eth_proto
Definition: cne_ether.h:77
uint8_t ether_addr_octet[ETH_ALEN]
Definition: cne_ether.h:53