Motr  M0
ip.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2021 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_NET
23 #include "lib/trace.h"
24 
25 #ifndef __KERNEL__
26 
27 #include "net/net_internal.h"
28 #include "lib/assert.h"
29 #include "lib/errno.h"
30 #include "lib/string.h"
31 #include <arpa/inet.h> /* inet_pton, htons */
32 #include <netdb.h> /* hostent */
33 #include <stdlib.h> /* atoi */
34 
35 static const char *ip_family[M0_NET_IP_AF_NR] = {
36  [M0_NET_IP_AF_INET] = "inet",
37  [M0_NET_IP_AF_INET6] = "inet6",
38  [M0_NET_IP_AF_UNIX] = "unix" };
39 
40 static const char *ip_protocol[M0_NET_IP_PROTO_NR] = {
41  [M0_NET_IP_PROTO_TCP] = "tcp",
42  [M0_NET_IP_PROTO_UDP] = "udp",
43  [M0_NET_IP_PROTO_VERBS] = "verbs",
44  [M0_NET_IP_PROTO_O2IB] = "o2ib" };
45 
46 /* This is the max strlen of members of ip_family and ip_protocol */
47 #define MAX_PREFIX_STRLEN 10
48 
52 static uint8_t ip_autotm[1024] = {};
53 
55 
59 static struct m0_mutex autotm_lock = {};
60 
65 static int m0_net_ip_to_hostname(const char *ip, char *hostname)
66 {
67  struct hostent *he;
68  struct in_addr addr;
69  int rc;
70 
71  inet_aton(ip, &addr);
72  he = gethostbyaddr(&addr, sizeof(addr), AF_INET);
73  if (he == NULL) {
74  M0_LOG(M0_ERROR, "gethostbyaddr err=%d for %s",
75  h_errno, (char*)ip);
76  /* Return error code for gethostbyaddr failure */
77  return M0_ERR(-h_errno);
78  }
79  M0_LOG(M0_DEBUG, "ip: %s to hostname: %s\n",ip, he->h_name);
80  rc = snprintf(hostname, M0_NET_IP_STRLEN_MAX, "%s", he->h_name);
81 
82  if (rc <= 0 || rc >= M0_NET_IP_STRLEN_MAX)
83  return M0_ERR(-EINVAL);
84 
85  return M0_RC(0);
86 }
87 
88 
89 static int parse_prefix(const char *ep_name, const char **prefixes,
90  int nr_prefixes, int *index, int *shift)
91 {
92  int i;
93 
94  for (i = 0; i < nr_prefixes; ++i) {
95  if (prefixes[i] != NULL) {
96  *shift = strnlen(prefixes[i], MAX_PREFIX_STRLEN);
97  if (strncmp(ep_name, prefixes[i], *shift) == 0) {
98  *index = i;
99  break;
100  }
101  }
102  }
103 
104  if (i >= nr_prefixes)
105  return M0_ERR(-EINVAL);
106 
107  return 0;
108 
109 }
110 
121 static int m0_net_ip_inet_parse(const char *name, struct m0_net_ip_addr *addr)
122 {
123  long int portnum;
124  int shift = 0;
125  int family = 0;
126  int type = 0;
127  int rc;
128  char ip[M0_NET_IP_STRLEN_MAX] = {};
129  char port[M0_NET_IP_PORTLEN_MAX] = {};
130  char *at;
131  const char *ep_name = name;
132  char *end;
133 
134  rc = parse_prefix(ep_name, ip_family, ARRAY_SIZE(ip_family), &family,
135  &shift);
136  if (rc != 0 || ep_name[shift] != ':')
137  return M0_ERR(-EINVAL);
138  ep_name += shift + 1;
139 
141  &shift);
142  if (rc != 0 || ep_name[shift] != ':')
143  return M0_ERR(-EINVAL);
144  ep_name += shift + 1;
145 
146  at = strchr(ep_name, '@');
147  if (at == NULL)
148  return M0_ERR(-EINVAL);
149  else {
150  at++;
151  if (at == NULL || !isdigit(at[0]))
152  return M0_ERR(-EINVAL);
153  strcpy(port, at);
154  portnum = strtol(port, &end, 10);
155  if (portnum > M0_NET_IP_PORT_MAX)
156  return M0_ERR(-EINVAL);
157  addr->nia_n.nip_port = (uint16_t)portnum;
158  }
159 
160  rc = m0_net_hostname_to_ip((char *)ep_name, ip,
161  &addr->nia_n.nip_format);
162  if (rc == 0)
163  inet_pton(family == M0_NET_IP_AF_INET ? AF_INET : AF_INET6,
164  ip, &addr->nia_n.nip_ip_n.sn[0]);
165 
166  /*
167  * To fix codacy warning for strlen, check only if the strnlen exceeds
168  * the array size of addr->nia_p.
169  */
170  M0_ASSERT(strnlen(name, ARRAY_SIZE(addr->nia_p) + 1 ) <
171  ARRAY_SIZE(addr->nia_p));
172  strcpy(addr->nia_p, name);
173  addr->nia_n.nip_fmt_pvt.ia.nia_family = family;
174  addr->nia_n.nip_fmt_pvt.ia.nia_type = type;
175 
176  /* Ignore the error due to gethostbyname() as it will be retried. */
177  return rc >= 0 ? M0_RC(0) : M0_ERR(rc);
178 }
179 
189 static int m0_net_ip_lnet_parse(const char *name, struct m0_net_ip_addr *addr)
190 {
191  char *at = NULL;
192  int nr;
193  int i;
194  int pid;
195  int portal;
196  int portnum;
197  int tmid;
198  char node[M0_NET_IP_STRLEN_MAX] = {};
199  char port[M0_NET_IP_PORTLEN_MAX] = {};
200  const char *ep_name = name;
201  uint32_t nia_n;
202  int shift;
203  int type = 0;
204  int rc;
205  bool is_localhost = false;
206 
207 
208  at = strchr(ep_name, '@');
209  if (strncmp(ep_name, "0@lo", 4) == 0) {
210  nia_n = htonl(INADDR_LOOPBACK);
211  inet_ntop(AF_INET, &nia_n, node, ARRAY_SIZE(node));
212  is_localhost = true;
213  } else {
214  if (at == NULL || at - ep_name >= sizeof node)
215  return M0_ERR(-EPROTO);
216 
217  M0_PRE(sizeof node >= (at-ep_name)+1);
218  memcpy(node, ep_name, at - ep_name);
219  at++;
221  &type, &shift);
222  if (rc != 0)
223  return M0_ERR(rc);
224  }
225 
226  if (at == NULL || (at = strchr(at, ':')) == NULL)
227  return M0_ERR(-EPROTO);
228 
229  nr = sscanf(at + 1, "%d:%d:%d", &pid, &portal, &tmid);
230  if (nr != 3) {
231  nr = sscanf(at + 1, "%d:%d:*", &pid, &portal);
232  if (nr != 2)
233  return M0_ERR(-EPROTO);
235  for (i = 0; i < IP_AUTOTM_NR; ++i) {
236  /*
237  * Start assigning auto-tm indices from the middle of
238  * the bitmap to avoid clashes within UT-s.
239  */
240  int probe = (i + IP_AUTOTM_NR / 2) % IP_AUTOTM_NR;
241  if (ip_autotm[probe] == 0) {
242  tmid = probe;
243  /* To handle '*' wildchar as tmid*/
244  addr->nia_n.nip_fmt_pvt.la.nla_autotm = true;
245  ip_autotm[tmid] = 1;
246  break;
247  }
248  }
250  if (i == ARRAY_SIZE(ip_autotm))
251  return M0_ERR(-EADDRNOTAVAIL);
252  } else
253  addr->nia_n.nip_fmt_pvt.la.nla_autotm = false;
254 
255  if (pid != 12345)
256  return M0_ERR(-EPROTO);
257  /*
258  * Deterministically combine portal and tmid into a unique 16-bit port
259  * number (greater than 1024). Tricky.
260  *
261  * Port number is, in binary: tttttttttt1ppppp, that is, 10 bits of tmid
262  * (which must be less than 1024), followed by a set bit (guaranteeing
263  * that the port is not reserved), followed by 5 bits of (portal - 30),
264  * so that portal must be in the range 30..61.
265  *
266  if (tmid >= 1024 || (portal - 30) >= 32)
267  return M0_ERR_INFO(-EPROTO,
268  "portal: %u, tmid: %u", portal, tmid);
269  */
270 
271  addr->nia_n.nip_fmt_pvt.la.nla_portal = (uint16_t)portal;
272  if (portal < 30)
273  portal = 30 + portal;
274 
275  portnum = tmid | (1 << 10) | ((portal - 30) << 11);
276  if (portnum > M0_NET_IP_PORT_MAX)
277  return M0_ERR(-EINVAL);
278  snprintf(port, ARRAY_SIZE(port), "%d", (uint32_t)portnum);
279  addr->nia_n.nip_format = M0_NET_IP_LNET_FORMAT;
280  inet_pton(AF_INET, node, &addr->nia_n.nip_ip_n.sn[0]);
281  addr->nia_n.nip_fmt_pvt.la.nla_tmid = (uint16_t)tmid;
282  addr->nia_n.nip_port = (uint16_t)portnum;
283  addr->nia_n.nip_fmt_pvt.la.nla_type = is_localhost ? 0xFF : type;
284  /*
285  * To fix codacy warning for strlen, check only if the strnlen exceeds
286  * the array size of addr->nia_p.
287  */
288  M0_ASSERT(strnlen(name, ARRAY_SIZE(addr->nia_p) + 1 ) <
289  ARRAY_SIZE(addr->nia_p));
290  strcpy(addr->nia_p, name);
291 
292  return M0_RC(0);
293 }
294 
298 static bool m0_net_ip_v4_eq(const uint32_t *a1, const uint32_t *a2)
299 {
300  return (a1[0] == a2[0]);
301 }
302 
306 static bool m0_net_ip_v6_eq(const uint64_t *a1, const uint64_t *a2)
307 {
308  return (a1[0] == a2[0] && a1[1] == a2[1]);
309 }
310 
314 static bool m0_net_ip_la_eq(const struct m0_net_ip_addr *a1,
315  const struct m0_net_ip_addr *a2)
316 {
317  const struct m0_net_ip_lnet_addr *la1 = &a1->nia_n.nip_fmt_pvt.la;
318  const struct m0_net_ip_lnet_addr *la2 = &a2->nia_n.nip_fmt_pvt.la;
319 
320  M0_PRE(a1 != NULL && a2 != NULL);
321 
322  return (la1->nla_type == la2->nla_type &&
323  la1->nla_portal == la2->nla_portal &&
324  la1->nla_tmid == la2->nla_tmid &&
325  la1->nla_autotm == la2->nla_autotm &&
327  &a2->nia_n.nip_ip_n.sn[0]));
328 }
329 
333 static bool m0_net_ip_ia_eq(const struct m0_net_ip_addr *a1,
334  const struct m0_net_ip_addr *a2)
335 {
336  const struct m0_net_ip_inet_addr *ia1 = &a1->nia_n.nip_fmt_pvt.ia;
337  const struct m0_net_ip_inet_addr *ia2 = &a2->nia_n.nip_fmt_pvt.ia;
338 
339  M0_PRE(a1 != NULL && a2 != NULL);
340 
341  return (ia1->nia_family == ia2->nia_family &&
342  ia1->nia_type == ia2->nia_type &&
343  ia1->nia_family == M0_NET_IP_AF_INET ?
345  &a2->nia_n.nip_ip_n.sn[0]) :
347  &a2->nia_n.nip_ip_n.ln[0]));
348 }
349 
350 M0_INTERNAL int m0_net_ip_parse(const char *name, struct m0_net_ip_addr *addr)
351 {
352  return isdigit(name[0]) ? m0_net_ip_lnet_parse(name, addr) :
354 }
355 
356 M0_INTERNAL int m0_net_ip_print(const struct m0_net_ip_addr *nia)
357 {
358  char ip_p[INET6_ADDRSTRLEN] = {};
359  char hostname[M0_NET_IP_STRLEN_MAX] = {};
360  char tmid[6] = {};
361  char *buf = (char *)nia->nia_p;
362  const struct m0_net_ip_params *na = &nia->nia_n;
363  int rc = 0;
364 
365  M0_ENTRY("frmt=%d nip_ip_n=[0x%" PRIx64 ",0x%" PRIx64 "] port=%d",
366  (int)na->nip_format, na->nip_ip_n.ln[0], na->nip_ip_n.ln[1],
367  (int)na->nip_port);
368 
369  if (na->nip_format == M0_NET_IP_LNET_FORMAT)
370  M0_LOG(M0_DEBUG, "type=%d portal=%d tmid=%d autotm=%s",
371  (int)na->nip_fmt_pvt.la.nla_type,
372  (int)na->nip_fmt_pvt.la.nla_portal,
373  (int)na->nip_fmt_pvt.la.nla_tmid,
374  na->nip_fmt_pvt.la.nla_autotm ? "true" : "false");
375  else
376  M0_LOG(M0_DEBUG, "family=%d type=%d",
377  (int)na->nip_fmt_pvt.ia.nia_family,
378  (int)na->nip_fmt_pvt.ia.nia_type);
379 
380  if (na->nip_format == M0_NET_IP_LNET_FORMAT) {
381  rc = na->nip_fmt_pvt.la.nla_autotm ?
382  snprintf(tmid, ARRAY_SIZE(tmid), "*") :
383  snprintf(tmid, ARRAY_SIZE(tmid), "%d",
384  na->nip_fmt_pvt.la.nla_tmid);
385  M0_ASSERT(rc < ARRAY_SIZE(tmid));
386  inet_ntop(AF_INET, &na->nip_ip_n.sn[0], ip_p, ARRAY_SIZE(ip_p));
387  rc = snprintf(buf, M0_NET_IP_STRLEN_MAX,
388  "%s@%s:12345:%d:%s",
389  na->nip_fmt_pvt.la.nla_type == 0xFF ? "0" : ip_p,
390  na->nip_fmt_pvt.la.nla_type == 0xFF ? "lo" :
391  ((na->nip_fmt_pvt.la.nla_type ==
392  M0_NET_IP_PROTO_TCP) ? "tcp": "o2ib"),
393  na->nip_fmt_pvt.la.nla_portal, tmid);
394  } else if (na->nip_format == M0_NET_IP_INET_IP_FORMAT) {
395  if (na->nip_fmt_pvt.ia.nia_family != M0_NET_IP_AF_UNIX) {
396  inet_ntop(na->nip_fmt_pvt.ia.nia_family ==
397  M0_NET_IP_AF_INET ? AF_INET : AF_INET6,
398  &na->nip_ip_n.sn[0], ip_p, ARRAY_SIZE(ip_p));
399  rc = snprintf(buf, M0_NET_IP_STRLEN_MAX, "%s:%s:%s@%d",
400  na->nip_fmt_pvt.ia.nia_family ==
401  M0_NET_IP_AF_INET ? "inet" : "inet6",
402  ip_protocol[na->nip_fmt_pvt.ia.nia_type],
403  ip_p, na->nip_port);
404  } else
405  M0_LOG(M0_ERROR, "Format is currently not supported");
406  } else if (na->nip_format == M0_NET_IP_INET_HOSTNAME_FORMAT) {
407  inet_ntop(AF_INET, &na->nip_ip_n.sn[0], ip_p, ARRAY_SIZE(ip_p));
408  rc = m0_net_ip_to_hostname(ip_p, hostname);
409  if (rc != 0 )
410  return M0_ERR(rc);
411  rc = snprintf(buf, M0_NET_IP_STRLEN_MAX, "inet:%s:%s@%d",
412  ip_protocol[na->nip_fmt_pvt.ia.nia_type],
413  hostname, na->nip_port);
414  }
415  if (rc <= 0 || rc >= M0_NET_IP_STRLEN_MAX)
416  return M0_ERR(-EINVAL);
417  M0_LOG(M0_DEBUG, "Address constructed: %s", buf);
418 
419  return 0;
420 }
421 
422 M0_INTERNAL int m0_net_hostname_to_ip(const char *hostname, char *ip,
423  enum m0_net_ip_format *fmt)
424 {
425  struct hostent *hname;
426  struct in_addr **addr;
427  uint32_t ip_n[4];
428  int i;
429  int n;
430  char *cp;
431  char name[M0_NET_IP_STRLEN_MAX] = {};
432 
433  M0_ENTRY("Hostname=%s", (char*)hostname);
434  cp = strchr(hostname, '@');
435  if (cp == NULL)
436  return M0_ERR(-EINVAL);
437 
438  n = cp - hostname;
439  name[n] = '\0';
440  strncat(name, hostname, n);
441 
442  if (inet_pton(AF_INET, name, &ip_n[0]) == 1 ||
443  inet_pton(AF_INET6, name, &ip_n[0]) == 1) {
444  /* Copy ip address as it is. */
446  strcpy(ip, name);
447  } else {
449  hname = gethostbyname(name);
450  if (hname == NULL) {
451  M0_LOG(M0_ERROR, "gethostbyname err=%d for %s",
452  h_errno, (char*)name);
453  /* Return positive rc for gethostbyname failure */
454  return M0_ERR(h_errno);
455  }
456  addr = (struct in_addr **)hname->h_addr_list;
457  for (i = 0; addr[i] != NULL; i++) {
458  /* Return the first one. */
459  strcpy(ip, inet_ntoa(*addr[i]));
460  M0_LOG(M0_DEBUG, "fqdn=%s to ip=%s", (char*)name, ip);
461  return M0_RC(0);
462  }
463 
464  /* If no valid addr structure found, then return error */
465  return M0_ERR(-errno);
466  }
467 
468  return M0_RC(0);
469 }
470 
471 M0_INTERNAL bool m0_net_ip_addr_eq(const struct m0_net_ip_addr *addr1,
472  const struct m0_net_ip_addr *addr2,
473  bool is_ncmp)
474 {
475  M0_PRE(addr1 != NULL && addr2 != NULL);
476  if (!is_ncmp)
477  return (strcmp(addr1->nia_p, addr2->nia_p) == 0);
478  else
479  return (addr1->nia_n.nip_format == addr2->nia_n.nip_format &&
480  addr1->nia_n.nip_port == addr2->nia_n.nip_port &&
481  /* For lnet address compare using m0_net_ip_la_eq(). */
482  ((addr1->nia_n.nip_format == M0_NET_IP_LNET_FORMAT &&
483  m0_net_ip_la_eq(addr1, addr2)) ||
484  /* For inet address compare using m0_net_ip_ia_eq(). */
486  m0_net_ip_ia_eq(addr1, addr2))));
487 }
488 
489 M0_INTERNAL int m0_net_ip_init(void)
490 {
493  return 0;
494 }
495 
496 M0_INTERNAL void m0_net_ip_fini(void)
497 {
499 }
500 
501 #endif /* __KERNEL__ */
502 
503 #undef M0_TRACE_SUBSYSTEM
504 
505 /*
506  * Local variables:
507  * c-indentation-style: "K&R"
508  * c-basic-offset: 8
509  * tab-width: 8
510  * fill-column: 80
511  * scroll-step: 1
512  * End:
513  */
union m0_net_ip_params::@378 nip_fmt_pvt
static bool m0_net_ip_v4_eq(const uint32_t *a1, const uint32_t *a2)
Definition: ip.c:298
struct m0_net_ip_lnet_addr la
Definition: ip.h:81
static size_t nr
Definition: dump.c:1505
#define M0_PRE(cond)
uint16_t nla_portal
Definition: ip.h:66
static const char * ip_protocol[M0_NET_IP_PROTO_NR]
Definition: ip.c:40
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
static int m0_net_ip_to_hostname(const char *ip, char *hostname)
Definition: ip.c:65
enum m0_net_ip_format nip_format
Definition: ip.h:73
#define NULL
Definition: misc.h:38
m0_net_ip_format
Definition: ip.h:33
M0_INTERNAL int m0_net_hostname_to_ip(const char *hostname, char *ip, enum m0_net_ip_format *fmt)
Definition: ip.c:422
union m0_net_ip_params::@377 nip_ip_n
static bool m0_net_ip_ia_eq(const struct m0_net_ip_addr *a1, const struct m0_net_ip_addr *a2)
Definition: ip.c:333
#define M0_LOG(level,...)
Definition: trace.h:167
uint16_t nia_family
Definition: ip.h:59
static struct net_test_cmd_node * node
Definition: commands.c:72
#define M0_NET_IP_PORTLEN_MAX
Definition: ip.h:29
static int m0_net_ip_lnet_parse(const char *name, struct m0_net_ip_addr *addr)
Definition: ip.c:189
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
M0_INTERNAL void m0_net_ip_fini(void)
Definition: ip.c:496
struct m0_net_ip_params nia_n
Definition: ip.h:87
#define PRIx64
Definition: types.h:61
Definition: sock.c:887
char nia_p[M0_NET_IP_STRLEN_MAX]
Definition: ip.h:88
M0_INTERNAL int m0_net_ip_print(const struct m0_net_ip_addr *nia)
Definition: ip.c:356
return M0_RC(rc)
#define M0_ENTRY(...)
Definition: trace.h:170
uint16_t nip_port
Definition: ip.h:78
static char * addr
Definition: node_k.c:37
bool nla_autotm
Definition: ip.h:68
int i
Definition: dir.c:1033
#define M0_SET_ARR0(arr)
Definition: misc.h:72
return M0_ERR(-EOPNOTSUPP)
static uint8_t ip_autotm[1024]
Definition: ip.c:52
static bool m0_net_ip_v6_eq(const uint64_t *a1, const uint64_t *a2)
Definition: ip.c:306
#define MAX_PREFIX_STRLEN
Definition: ip.c:47
const char * name
Definition: trace.c:110
struct m0_net_ip_inet_addr ia
Definition: ip.h:80
#define M0_ASSERT(cond)
uint16_t nla_type
Definition: ip.h:65
char * fmt(const char *format,...) __attribute__((format(printf
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
Definition: xcode.h:73
M0_INTERNAL int m0_net_ip_init(void)
Definition: ip.c:489
static int parse_prefix(const char *ep_name, const char **prefixes, int nr_prefixes, int *index, int *shift)
Definition: ip.c:89
static bool at(struct ff2c_context *ctx, char c)
Definition: lex.c:77
static int m0_net_ip_inet_parse(const char *name, struct m0_net_ip_addr *addr)
Definition: ip.c:121
uint64_t n
Definition: fops.h:107
uint16_t nla_tmid
Definition: ip.h:67
uint16_t nia_type
Definition: ip.h:60
M0_INTERNAL int m0_net_ip_parse(const char *name, struct m0_net_ip_addr *addr)
Definition: ip.c:350
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
uint64_t ln[2]
Definition: ip.h:75
uint32_t sn[4]
Definition: ip.h:76
static bool m0_net_ip_la_eq(const struct m0_net_ip_addr *a1, const struct m0_net_ip_addr *a2)
Definition: ip.c:314
#define M0_NET_IP_STRLEN_MAX
Definition: ip.h:28
int type
Definition: dir.c:1031
Definition: mutex.h:47
static struct m0_mutex autotm_lock
Definition: ip.c:59
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
#define M0_NET_IP_PORT_MAX
Definition: ip.h:30
static const char * ip_family[M0_NET_IP_AF_NR]
Definition: ip.c:35
M0_INTERNAL bool m0_net_ip_addr_eq(const struct m0_net_ip_addr *addr1, const struct m0_net_ip_addr *addr2, bool is_ncmp)
Definition: ip.c:471