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 
57 static struct m0_mutex autotm_lock = {};
58 
63 static int m0_net_ip_to_hostname(const char *ip, char *hostname)
64 {
65  struct hostent *he;
66  struct in_addr addr;
67  int rc;
68 
69  inet_aton(ip, &addr);
70  he = gethostbyaddr(&addr, sizeof(addr), AF_INET);
71  if (he == NULL) {
72  M0_LOG(M0_ERROR, "gethostbyaddr err=%d for %s",
73  h_errno, (char*)ip);
74  /* Return error code for gethostbyaddr failure */
75  return M0_ERR(-h_errno);
76  }
77  M0_LOG(M0_DEBUG, "ip: %s to hostname: %s\n",ip, he->h_name);
78  rc = snprintf(hostname, M0_NET_IP_STRLEN_MAX, "%s", he->h_name);
79 
80  if (rc <= 0 || rc >= M0_NET_IP_STRLEN_MAX)
81  return M0_ERR(-EINVAL);
82 
83  return M0_RC(0);
84 }
85 
86 
87 static int parse_prefix(const char *ep_name, const char **prefixes,
88  int nr_prefixes, int *index, int *shift)
89 {
90  int i;
91 
92  for (i = 0; i < nr_prefixes; ++i) {
93  if (prefixes[i] != NULL) {
94  *shift = strnlen(prefixes[i], MAX_PREFIX_STRLEN);
95  if (strncmp(ep_name, prefixes[i], *shift) == 0) {
96  *index = i;
97  break;
98  }
99  }
100  }
101 
102  if (i >= nr_prefixes)
103  return M0_ERR(-EINVAL);
104 
105  return 0;
106 
107 }
108 
119 static int m0_net_ip_inet_parse(const char *name, struct m0_net_ip_addr *addr)
120 {
121  long int portnum;
122  int shift = 0;
123  int family = 0;
124  int type = 0;
125  int rc;
126  char ip[M0_NET_IP_STRLEN_MAX] = {};
127  char port[M0_NET_IP_PORTLEN_MAX] = {};
128  char *at;
129  const char *ep_name = name;
130  char *end;
131 
132  rc = parse_prefix(ep_name, ip_family, ARRAY_SIZE(ip_family), &family,
133  &shift);
134  if (rc != 0 || ep_name[shift] != ':')
135  return M0_ERR(-EINVAL);
136  ep_name += shift + 1;
137 
139  &shift);
140  if (rc != 0 || ep_name[shift] != ':')
141  return M0_ERR(-EINVAL);
142  ep_name += shift + 1;
143 
144  at = strchr(ep_name, '@');
145  if (at == NULL)
146  return M0_ERR(-EINVAL);
147  else {
148  at++;
149  if (at == NULL || !isdigit(at[0]))
150  return M0_ERR(-EINVAL);
151  strcpy(port, at);
152  portnum = strtol(port, &end, 10);
153  if (portnum > M0_NET_IP_PORT_MAX)
154  return M0_ERR(-EINVAL);
155  addr->nia_n.nip_port = (uint16_t)portnum;
156  }
157 
158  rc = m0_net_hostname_to_ip((char *)ep_name, ip,
159  &addr->nia_n.nip_format);
160  if (rc == 0)
161  inet_pton(family == M0_NET_IP_AF_INET ? AF_INET : AF_INET6,
162  ip, &addr->nia_n.nip_ip_n.sn[0]);
163 
164  /*
165  * To fix codacy warning for strlen, check only if the strnlen exceeds
166  * the array size of addr->nia_p.
167  */
168  M0_ASSERT(strnlen(name, ARRAY_SIZE(addr->nia_p) + 1 ) <
169  ARRAY_SIZE(addr->nia_p));
170  strcpy(addr->nia_p, name);
171  addr->nia_n.nip_fmt_pvt.ia.nia_family = family;
172  addr->nia_n.nip_fmt_pvt.ia.nia_type = type;
173 
174  /* Ignore the error due to gethostbyname() as it will be retried. */
175  return rc >= 0 ? M0_RC(0) : M0_ERR(rc);
176 }
177 
187 static int m0_net_ip_lnet_parse(const char *name, struct m0_net_ip_addr *addr)
188 {
189  char *at = NULL;
190  int nr;
191  int i;
192  int pid;
193  int portal;
194  int portnum;
195  int tmid;
196  char node[M0_NET_IP_STRLEN_MAX] = {};
197  char port[M0_NET_IP_PORTLEN_MAX] = {};
198  const char *ep_name = name;
199  uint32_t nia_n;
200  int shift;
201  int type = 0;
202  int rc;
203  bool is_localhost = false;
204 
205 
206  at = strchr(ep_name, '@');
207  if (strncmp(ep_name, "0@lo", 4) == 0) {
208  nia_n = htonl(INADDR_LOOPBACK);
209  inet_ntop(AF_INET, &nia_n, node, ARRAY_SIZE(node));
210  is_localhost = true;
211  } else {
212  if (at == NULL || at - ep_name >= sizeof node)
213  return M0_ERR(-EPROTO);
214 
215  M0_PRE(sizeof node >= (at-ep_name)+1);
216  memcpy(node, ep_name, at - ep_name);
217  at++;
219  &type, &shift);
220  if (rc != 0)
221  return M0_ERR(rc);
222  }
223 
224  if (at == NULL || (at = strchr(at, ':')) == NULL)
225  return M0_ERR(-EPROTO);
226 
227  nr = sscanf(at + 1, "%d:%d:%d", &pid, &portal, &tmid);
228  if (nr != 3) {
229  nr = sscanf(at + 1, "%d:%d:*", &pid, &portal);
230  if (nr != 2)
231  return M0_ERR(-EPROTO);
233  for (i = 0; i < ARRAY_SIZE(ip_autotm); ++i) {
234  if (ip_autotm[i] == 0) {
235  tmid = i;
236  /* To handle '*' wildchar as tmid*/
237  addr->nia_n.nip_fmt_pvt.la.nla_autotm = true;
238  ip_autotm[tmid] = 1;
239  break;
240  }
241  }
243  if (i == ARRAY_SIZE(ip_autotm))
244  return M0_ERR(-EADDRNOTAVAIL);
245  } else
246  addr->nia_n.nip_fmt_pvt.la.nla_autotm = false;
247 
248  if (pid != 12345)
249  return M0_ERR(-EPROTO);
250  /*
251  * Deterministically combine portal and tmid into a unique 16-bit port
252  * number (greater than 1024). Tricky.
253  *
254  * Port number is, in binary: tttttttttt1ppppp, that is, 10 bits of tmid
255  * (which must be less than 1024), followed by a set bit (guaranteeing
256  * that the port is not reserved), followed by 5 bits of (portal - 30),
257  * so that portal must be in the range 30..61.
258  *
259  if (tmid >= 1024 || (portal - 30) >= 32)
260  return M0_ERR_INFO(-EPROTO,
261  "portal: %u, tmid: %u", portal, tmid);
262  */
263 
264  addr->nia_n.nip_fmt_pvt.la.nla_portal = (uint16_t)portal;
265  if (portal < 30)
266  portal = 30 + portal;
267 
268  portnum = tmid | (1 << 10) | ((portal - 30) << 11);
269  if (portnum > M0_NET_IP_PORT_MAX)
270  return M0_ERR(-EINVAL);
271  snprintf(port, ARRAY_SIZE(port), "%d", (uint32_t)portnum);
272  addr->nia_n.nip_format = M0_NET_IP_LNET_FORMAT;
273  inet_pton(AF_INET, node, &addr->nia_n.nip_ip_n.sn[0]);
274  addr->nia_n.nip_fmt_pvt.la.nla_tmid = (uint16_t)tmid;
275  addr->nia_n.nip_port = (uint16_t)portnum;
276  addr->nia_n.nip_fmt_pvt.la.nla_type = is_localhost ? 0xFF : type;
277  /*
278  * To fix codacy warning for strlen, check only if the strnlen exceeds
279  * the array size of addr->nia_p.
280  */
281  M0_ASSERT(strnlen(name, ARRAY_SIZE(addr->nia_p) + 1 ) <
282  ARRAY_SIZE(addr->nia_p));
283  strcpy(addr->nia_p, name);
284 
285  return M0_RC(0);
286 }
287 
291 static bool m0_net_ip_v4_eq(const uint32_t *a1, const uint32_t *a2)
292 {
293  return (a1[0] == a2[0]);
294 }
295 
299 static bool m0_net_ip_v6_eq(const uint64_t *a1, const uint64_t *a2)
300 {
301  return (a1[0] == a2[0] && a1[1] == a2[1]);
302 }
303 
307 static bool m0_net_ip_la_eq(const struct m0_net_ip_addr *a1,
308  const struct m0_net_ip_addr *a2)
309 {
310  const struct m0_net_ip_lnet_addr *la1 = &a1->nia_n.nip_fmt_pvt.la;
311  const struct m0_net_ip_lnet_addr *la2 = &a2->nia_n.nip_fmt_pvt.la;
312 
313  M0_PRE(a1 != NULL && a2 != NULL);
314 
315  return (la1->nla_type == la2->nla_type &&
316  la1->nla_portal == la2->nla_portal &&
317  la1->nla_tmid == la2->nla_tmid &&
318  la1->nla_autotm == la2->nla_autotm &&
320  &a2->nia_n.nip_ip_n.sn[0]));
321 }
322 
326 static bool m0_net_ip_ia_eq(const struct m0_net_ip_addr *a1,
327  const struct m0_net_ip_addr *a2)
328 {
329  const struct m0_net_ip_inet_addr *ia1 = &a1->nia_n.nip_fmt_pvt.ia;
330  const struct m0_net_ip_inet_addr *ia2 = &a2->nia_n.nip_fmt_pvt.ia;
331 
332  M0_PRE(a1 != NULL && a2 != NULL);
333 
334  return (ia1->nia_family == ia2->nia_family &&
335  ia1->nia_type == ia2->nia_type &&
336  ia1->nia_family == M0_NET_IP_AF_INET ?
338  &a2->nia_n.nip_ip_n.sn[0]) :
340  &a2->nia_n.nip_ip_n.ln[0]));
341 }
342 
343 M0_INTERNAL int m0_net_ip_parse(const char *name, struct m0_net_ip_addr *addr)
344 {
345  return isdigit(name[0]) ? m0_net_ip_lnet_parse(name, addr) :
347 }
348 
349 M0_INTERNAL int m0_net_ip_print(const struct m0_net_ip_addr *nia)
350 {
351  char ip_p[INET6_ADDRSTRLEN] = {};
352  char hostname[M0_NET_IP_STRLEN_MAX] = {};
353  char tmid[6] = {};
354  char *buf = (char *)nia->nia_p;
355  const struct m0_net_ip_params *na = &nia->nia_n;
356  int rc = 0;
357 
358  M0_ENTRY("frmt=%d nip_ip_n=[0x%" PRIx64 ",0x%" PRIx64 "] port=%d",
359  (int)na->nip_format, na->nip_ip_n.ln[0], na->nip_ip_n.ln[1],
360  (int)na->nip_port);
361 
362  if (na->nip_format == M0_NET_IP_LNET_FORMAT)
363  M0_LOG(M0_DEBUG, "type=%d portal=%d tmid=%d autotm=%s",
364  (int)na->nip_fmt_pvt.la.nla_type,
365  (int)na->nip_fmt_pvt.la.nla_portal,
366  (int)na->nip_fmt_pvt.la.nla_tmid,
367  na->nip_fmt_pvt.la.nla_autotm ? "true" : "false");
368  else
369  M0_LOG(M0_DEBUG, "family=%d type=%d",
370  (int)na->nip_fmt_pvt.ia.nia_family,
371  (int)na->nip_fmt_pvt.ia.nia_type);
372 
373  if (na->nip_format == M0_NET_IP_LNET_FORMAT) {
374  rc = na->nip_fmt_pvt.la.nla_autotm ?
375  snprintf(tmid, ARRAY_SIZE(tmid), "*") :
376  snprintf(tmid, ARRAY_SIZE(tmid), "%d",
377  na->nip_fmt_pvt.la.nla_tmid);
378  M0_ASSERT(rc < ARRAY_SIZE(tmid));
379  inet_ntop(AF_INET, &na->nip_ip_n.sn[0], ip_p, ARRAY_SIZE(ip_p));
380  rc = snprintf(buf, M0_NET_IP_STRLEN_MAX,
381  "%s@%s:12345:%d:%s",
382  na->nip_fmt_pvt.la.nla_type == 0xFF ? "0" : ip_p,
383  na->nip_fmt_pvt.la.nla_type == 0xFF ? "lo" :
384  ((na->nip_fmt_pvt.la.nla_type ==
385  M0_NET_IP_PROTO_TCP) ? "tcp": "o2ib"),
386  na->nip_fmt_pvt.la.nla_portal, tmid);
387  } else if (na->nip_format == M0_NET_IP_INET_IP_FORMAT) {
388  if (na->nip_fmt_pvt.ia.nia_family != M0_NET_IP_AF_UNIX) {
389  inet_ntop(na->nip_fmt_pvt.ia.nia_family ==
390  M0_NET_IP_AF_INET ? AF_INET : AF_INET6,
391  &na->nip_ip_n.sn[0], ip_p, ARRAY_SIZE(ip_p));
392  rc = snprintf(buf, M0_NET_IP_STRLEN_MAX, "%s:%s:%s@%d",
393  na->nip_fmt_pvt.ia.nia_family ==
394  M0_NET_IP_AF_INET ? "inet" : "inet6",
395  ip_protocol[na->nip_fmt_pvt.ia.nia_type],
396  ip_p, na->nip_port);
397  } else
398  M0_LOG(M0_ERROR, "Format is currently not supported");
399  } else if (na->nip_format == M0_NET_IP_INET_HOSTNAME_FORMAT) {
400  inet_ntop(AF_INET, &na->nip_ip_n.sn[0], ip_p, ARRAY_SIZE(ip_p));
401  rc = m0_net_ip_to_hostname(ip_p, hostname);
402  if (rc != 0 )
403  return M0_ERR(rc);
404  rc = snprintf(buf, M0_NET_IP_STRLEN_MAX, "inet:%s:%s@%d",
405  ip_protocol[na->nip_fmt_pvt.ia.nia_type],
406  hostname, na->nip_port);
407  }
408  if (rc <= 0 || rc >= M0_NET_IP_STRLEN_MAX)
409  return M0_ERR(-EINVAL);
410  M0_LOG(M0_DEBUG, "Address constructed: %s", buf);
411 
412  return 0;
413 }
414 
415 M0_INTERNAL int m0_net_hostname_to_ip(const char *hostname, char *ip,
416  enum m0_net_ip_format *fmt)
417 {
418  struct hostent *hname;
419  struct in_addr **addr;
420  uint32_t ip_n[4];
421  int i;
422  int n;
423  char *cp;
424  char name[M0_NET_IP_STRLEN_MAX] = {};
425 
426  M0_ENTRY("Hostname=%s", (char*)hostname);
427  cp = strchr(hostname, '@');
428  if (cp == NULL)
429  return M0_ERR(-EINVAL);
430 
431  n = cp - hostname;
432  name[n] = '\0';
433  strncat(name, hostname, n);
434 
435  if (inet_pton(AF_INET, name, &ip_n[0]) == 1 ||
436  inet_pton(AF_INET6, name, &ip_n[0]) == 1) {
437  /* Copy ip address as it is. */
439  strcpy(ip, name);
440  } else {
442  hname = gethostbyname(name);
443  if (hname == NULL) {
444  M0_LOG(M0_ERROR, "gethostbyname err=%d for %s",
445  h_errno, (char*)name);
446  /* Return positive rc for gethostbyname failure */
447  return M0_ERR(h_errno);
448  }
449  addr = (struct in_addr **)hname->h_addr_list;
450  for (i = 0; addr[i] != NULL; i++) {
451  /* Return the first one. */
452  strcpy(ip, inet_ntoa(*addr[i]));
453  M0_LOG(M0_DEBUG, "fqdn=%s to ip=%s", (char*)name, ip);
454  return M0_RC(0);
455  }
456 
457  /* If no valid addr structure found, then return error */
458  return M0_ERR(-errno);
459  }
460 
461  return M0_RC(0);
462 }
463 
464 M0_INTERNAL bool m0_net_ip_addr_eq(const struct m0_net_ip_addr *addr1,
465  const struct m0_net_ip_addr *addr2,
466  bool is_ncmp)
467 {
468  M0_PRE(addr1 != NULL && addr2 != NULL);
469  if (!is_ncmp)
470  return (strcmp(addr1->nia_p, addr2->nia_p) == 0);
471  else
472  return (addr1->nia_n.nip_format == addr2->nia_n.nip_format &&
473  addr1->nia_n.nip_port == addr2->nia_n.nip_port &&
474  /* For lnet address compare using m0_net_ip_la_eq(). */
475  ((addr1->nia_n.nip_format == M0_NET_IP_LNET_FORMAT &&
476  m0_net_ip_la_eq(addr1, addr2)) ||
477  /* For inet address compare using m0_net_ip_ia_eq(). */
479  m0_net_ip_ia_eq(addr1, addr2))));
480 }
481 
482 M0_INTERNAL int m0_net_ip_init(void)
483 {
486  return 0;
487 }
488 
489 M0_INTERNAL void m0_net_ip_fini(void)
490 {
492 }
493 
494 #endif /* __KERNEL__ */
495 
496 #undef M0_TRACE_SUBSYSTEM
497 
498 /*
499  * Local variables:
500  * c-indentation-style: "K&R"
501  * c-basic-offset: 8
502  * tab-width: 8
503  * fill-column: 80
504  * scroll-step: 1
505  * End:
506  */
union m0_net_ip_params::@377 nip_fmt_pvt
static bool m0_net_ip_v4_eq(const uint32_t *a1, const uint32_t *a2)
Definition: ip.c:291
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:63
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:415
static bool m0_net_ip_ia_eq(const struct m0_net_ip_addr *a1, const struct m0_net_ip_addr *a2)
Definition: ip.c:326
#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:187
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:489
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:349
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:299
#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
union m0_net_ip_params::@376 nip_ip_n
#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:482
static int parse_prefix(const char *ep_name, const char **prefixes, int nr_prefixes, int *index, int *shift)
Definition: ip.c:87
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:119
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:343
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:307
#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:57
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:464