netns.c revision 9f07da4a
1/*
2 * Copyright (c) 2016 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <librtnl/netns.h>
17
18#include <vnet/ip/format.h>
19#include <vnet/ethernet/ethernet.h>
20
21#include <stddef.h>
22
23/* Enable some RTA values debug */
24//#define RTNL_CHECK
25
26#define is_nonzero(x)                      \
27  ({                                       \
28    u8 __is_zero_zero[sizeof(x)] = {};     \
29    memcmp(__is_zero_zero, &x, sizeof(x)); \
30  })
31
32typedef struct {
33  u8 type;      //Attribute identifier
34  u8 unique;    //Part of the values uniquely identifying an entry
35  u16 offset;   //Offset where stored in struct
36  u16 size;     //Length of the attribute
37} rtnl_mapping_t;
38
39#define ns_foreach_ifla           \
40  _(IFLA_ADDRESS, hwaddr)         \
41  _(IFLA_BROADCAST, broadcast)    \
42  _(IFLA_IFNAME, ifname)          \
43  _(IFLA_MASTER, master)          \
44  _(IFLA_MTU, mtu)                \
45  _(IFLA_QDISC, qdisc)
46
47static rtnl_mapping_t ns_ifmap[] = {
48#define _(t, e)                        \
49{                                      \
50    .type = t,                         \
51    .offset = offsetof(ns_link_t, e),  \
52    .size = sizeof(((ns_link_t*)0)->e) \
53},
54    ns_foreach_ifla
55#undef _
56  { .type = 0 }
57};
58
59u8 *format_ns_link (u8 *s, va_list *args)
60{
61  ns_link_t *l = va_arg(*args, ns_link_t *);
62  s = format(s, "%s index %u", l->ifname, l->ifi.ifi_index);
63  return s;
64}
65
66#define ns_foreach_rta                \
67  _(RTA_DST, dst, 1)                  \
68  _(RTA_SRC, src, 1)                  \
69  _(RTA_GATEWAY, gateway, 1)          \
70  _(RTA_IIF, iif, 1)                  \
71  _(RTA_OIF, oif, 1)                  \
72  _(RTA_PREFSRC, prefsrc, 0)          \
73  _(RTA_TABLE, table, 0)              \
74  _(RTA_PRIORITY, priority, 0)        \
75  _(RTA_CACHEINFO, cacheinfo, 0)
76
77static rtnl_mapping_t ns_routemap[] = {
78#define _(t, e, u)                      \
79{                                       \
80    .type = t, .unique = u,             \
81    .offset = offsetof(ns_route_t, e),  \
82    .size = sizeof(((ns_route_t*)0)->e) \
83},
84    ns_foreach_rta
85#undef _
86  { .type = 0 }
87};
88
89u8 *format_ns_route (u8 *s, va_list *args)
90{
91  ns_route_t *r = va_arg(*args, ns_route_t *);
92  void *format_ip = r->rtm.rtm_family == AF_INET ? format_ip4_address : format_ip6_address;
93  s = format(s, "%U/%d", format_ip, r->dst, r->rtm.rtm_dst_len);
94  if (r->rtm.rtm_src_len)
95    s = format(s, " from %U/%d", format_ip, r->src, r->rtm.rtm_src_len);
96  if (is_nonzero(r->gateway))
97    s = format(s, " via %U", format_ip, r->gateway);
98  if (r->iif)
99    s = format(s, " iif %d", r->iif);
100  if (r->oif)
101    s = format(s, " oif %d", r->oif);
102  if (is_nonzero(r->prefsrc))
103    s = format(s, " src %U", format_ip, r->prefsrc);
104  if (r->table)
105    s = format(s, " table %d", r->table);
106  if (r->priority)
107    s = format(s, " priority %u", r->priority);
108  return s;
109}
110
111#define ns_foreach_ifaddr         \
112  _(IFA_ADDRESS, addr, 1)         \
113  _(IFA_LOCAL, local, 1)          \
114  _(IFA_LABEL, label, 0)          \
115  _(IFA_BROADCAST, broadcast, 0)  \
116  _(IFA_ANYCAST, anycast, 0)      \
117  _(IFA_CACHEINFO, cacheinfo, 0)
118
119static rtnl_mapping_t ns_addrmap[] = {
120#define _(t, e, u)                      \
121{                                       \
122    .type = t, .unique = u,             \
123    .offset = offsetof(ns_addr_t, e),   \
124    .size = sizeof(((ns_addr_t*)0)->e)  \
125},
126    ns_foreach_ifaddr
127#undef _
128  { .type = 0 }
129};
130
131u8 *format_ns_addr (u8 *s, va_list *args)
132{
133  ns_addr_t *a = va_arg(*args, ns_addr_t *);
134  void *format_ip = a->ifaddr.ifa_family == AF_INET ? format_ip4_address : format_ip6_address;
135  s = format(s, "%U/%d", format_ip, a->addr, a->ifaddr.ifa_prefixlen);
136  if (is_nonzero(a->label))
137    s = format(s, " dev %s", a->label);
138  if (is_nonzero(a->broadcast))
139    s = format(s, " broadcast %U", format_ip, a->broadcast);
140  if (is_nonzero(a->anycast))
141    s = format(s, " anycast %U", format_ip, a->anycast);
142  if (is_nonzero(a->local))
143      s = format(s, " local %U", format_ip, a->local);
144  return s;
145}
146
147#ifndef NDA_RTA
148#define NDA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
149#define NDA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ndmsg))
150#endif
151
152#define ns_foreach_neigh         \
153  _(NDA_DST, dst, 1)             \
154  _(NDA_LLADDR, lladdr, 0)       \
155  _(NDA_PROBES, probes, 0)       \
156  _(NDA_CACHEINFO, cacheinfo, 0)
157
158static rtnl_mapping_t ns_neighmap[] = {
159#define _(t, e, u)                      \
160{                                       \
161    .type = t, .unique = u,             \
162    .offset = offsetof(ns_neigh_t, e),  \
163    .size = sizeof(((ns_neigh_t*)0)->e) \
164},
165    ns_foreach_neigh
166#undef _
167  { .type = 0 }
168};
169
170u8 *format_ns_neigh (u8 *s, va_list *args)
171{
172  ns_neigh_t *n = va_arg(*args, ns_neigh_t *);
173  void *format_ip = n->nd.ndm_family == AF_INET ? format_ip4_address : format_ip6_address;
174  s = format(s, "%U", format_ip, n->dst);
175  if (is_nonzero(n->lladdr))
176    s = format(s, " lladdr %U", format_ethernet_address, n->lladdr);
177  if (n->probes)
178      s = format(s, " probes %d", n->probes);
179  return s;
180}
181
182typedef struct {
183  void (*notify)(void *obj, netns_type_t type, u32 flags, uword opaque);
184  uword opaque;
185  u32 netns_index;
186} netns_handle_t;
187
188typedef struct {
189  netns_t netns;
190  u32 rtnl_handle;
191  u32 subscriber_count;
192} netns_p;
193
194typedef struct {
195  netns_p *netnss;
196  netns_handle_t *handles;
197} netns_main_t;
198
199netns_main_t netns_main;
200
201static int
202rtnl_parse_rtattr(struct rtattr *db[], size_t max,
203                  struct rtattr *rta, size_t len) {
204  for(; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
205    if (rta->rta_type <= max)
206      db[rta->rta_type] = rta;
207#ifdef RTNL_CHECK
208    else
209      clib_warning("RTA type too high: %d", rta->rta_type);
210#endif
211  }
212
213  if(len) {
214    clib_warning("rattr lenght mistmatch %d %d len",
215                 (int) len, (int) rta->rta_len);
216    return -1;
217  }
218  return 0;
219}
220
221/*
222 * Debug function to display when
223 * we receive an RTA that I forgot in
224 * the mapping table (there are so many of them).
225 */
226#ifdef RTNL_CHECK
227static void
228rtnl_entry_check(struct rtattr *rtas[],
229                 size_t rta_len,
230                 rtnl_mapping_t map[],
231                 char *logstr)
232{
233  int i;
234  for (i=0; i<rta_len; i++) {
235    if (!rtas[i])
236      continue;
237
238    rtnl_mapping_t *m = map;
239    for (m = map; m->type; m++) {
240      if (m->type == rtas[i]->rta_type)
241        break;
242    }
243    if (!m->type)
244      clib_warning("Unknown RTA type %d (%s)", rtas[i]->rta_type, logstr);
245  }
246}
247#endif
248
249/*
250 * Check if the provided entry matches the parsed and unique rtas
251 */
252static int
253rtnl_entry_match(void *entry,
254                 struct rtattr *rtas[],
255                 rtnl_mapping_t map[])
256{
257  u8 zero[1024] = {};
258  for ( ;map->type != 0; map++) {
259    struct rtattr *rta = rtas[map->type];
260    size_t rta_len = rta?RTA_PAYLOAD(rta):0;
261    if (!map->unique)
262      continue;
263
264    if (rta && RTA_PAYLOAD(rta) > map->size) {
265      clib_warning("rta (type=%d len=%d) too long (max %d)",
266                   rta->rta_type, rta->rta_len, map->size);
267      return -1;
268    }
269
270    if ((rta && memcmp(RTA_DATA(rta), entry + map->offset, rta_len)) ||
271        memcmp(entry + map->offset + rta_len, zero, map->size - rta_len)) {
272      return 0;
273    }
274  }
275  return 1;
276}
277
278static int
279rtnl_entry_set(void *entry,
280               struct rtattr *rtas[],
281               rtnl_mapping_t map[],
282               int init)
283{
284  for (; map->type != 0; map++) {
285    struct rtattr *rta = rtas[map->type];
286    if (rta) {
287      if (RTA_PAYLOAD(rta) > map->size) {
288        clib_warning("rta (type=%d len=%d) too long (max %d)",
289                           rta->rta_type, rta->rta_len, map->size);
290        return -1;
291      }
292
293      memcpy(entry + map->offset, RTA_DATA(rta), RTA_PAYLOAD(rta));
294      memset(entry + map->offset + RTA_PAYLOAD(rta), 0, map->size - RTA_PAYLOAD(rta));
295    } else if (init) {
296      memset(entry + map->offset, 0, map->size);
297    }
298  }
299  return 0;
300}
301
302void
303netns_notify(netns_p *ns, void *obj, netns_type_t type, u32 flags)
304{
305  netns_main_t *nm = &netns_main;
306  netns_handle_t *h;
307  pool_foreach(h, nm->handles, {
308     if (h->netns_index == (ns - nm->netnss) &&  h->notify)
309       h->notify(obj, type, flags, h->opaque);
310  });
311}
312
313static_always_inline int
314mask_match(void *a, void *b, void *mask, size_t len)
315{
316  u8 *va = (u8 *) a;
317  u8 *vb = (u8 *) b;
318  u8 *vm = (u8 *) mask;
319  while (len--) {
320    if ((va[len] ^ vb[len]) & vm[len])
321      return 0;
322  }
323  return 1;
324}
325
326static ns_link_t *
327ns_get_link(netns_p *ns, struct ifinfomsg *ifi, struct rtattr *rtas[])
328{
329  ns_link_t *link;
330  pool_foreach(link, ns->netns.links, {
331      if(ifi->ifi_index == link->ifi.ifi_index)
332        return link;
333  });
334  return NULL;
335}
336
337static int
338ns_rcv_link(netns_p *ns, struct nlmsghdr *hdr)
339{
340  ns_link_t *link;
341  struct ifinfomsg *ifi;
342  struct rtattr *rtas[IFLA_MAX + 1] = {};
343  size_t datalen = hdr->nlmsg_len - NLMSG_ALIGN(sizeof(*hdr));
344
345  if(datalen < sizeof(*ifi))
346      return -1;
347
348  ifi = NLMSG_DATA(hdr);
349  if((datalen > NLMSG_ALIGN(sizeof(*ifi))) &&
350      rtnl_parse_rtattr(rtas, IFLA_MAX, IFLA_RTA(ifi),
351                        IFLA_PAYLOAD(hdr))) {
352    return -1;
353  }
354#ifdef RTNL_CHECK
355  rtnl_entry_check(rtas, IFLA_MAX + 1, ns_ifmap, "link");
356#endif
357
358  link = ns_get_link(ns, ifi, rtas);
359
360  if (hdr->nlmsg_type == RTM_DELLINK) {
361    if (!link)
362      return -1;
363    pool_put(ns->netns.links, link);
364    netns_notify(ns, link, NETNS_TYPE_LINK, NETNS_F_DEL);
365    return 0;
366  }
367
368  if (!link) {
369    pool_get(ns->netns.links, link);
370    rtnl_entry_set(link, rtas, ns_ifmap, 1);
371  } else {
372    rtnl_entry_set(link, rtas, ns_ifmap, 0);
373  }
374
375  link->ifi = *ifi;
376  link->last_updated = vlib_time_now(vlib_get_main());
377  netns_notify(ns, link, NETNS_TYPE_LINK, NETNS_F_ADD);
378  return 0;
379}
380
381static ns_route_t *
382ns_get_route(netns_p *ns, struct rtmsg *rtm, struct rtattr *rtas[])
383{
384  ns_route_t *route;
385
386  //This describes the values which uniquely identify a route
387  struct rtmsg msg = {
388      .rtm_family = 0xff,
389      .rtm_dst_len = 0xff,
390      .rtm_src_len = 0xff,
391      .rtm_table = 0xff,
392      .rtm_protocol = 0xff,
393      .rtm_type = 0xff
394  };
395
396  pool_foreach(route, ns->netns.routes, {
397      if(mask_match(&route->rtm, rtm, &msg, sizeof(struct rtmsg)) &&
398          rtnl_entry_match(route, rtas, ns_routemap))
399        return route;
400  });
401  return NULL;
402}
403
404static int
405ns_rcv_route(netns_p *ns, struct nlmsghdr *hdr)
406{
407  ns_route_t *route;
408  struct rtmsg *rtm;
409  struct rtattr *rtas[RTA_MAX + 1] = {};
410  size_t datalen = hdr->nlmsg_len - NLMSG_ALIGN(sizeof(*hdr));
411
412  if(datalen < sizeof(*rtm))
413    return -1;
414
415  rtm = NLMSG_DATA(hdr);
416  if((datalen > NLMSG_ALIGN(sizeof(*rtm))) &&
417      rtnl_parse_rtattr(rtas, RTA_MAX, RTM_RTA(rtm),
418                        RTM_PAYLOAD(hdr))) {
419    return -1;
420  }
421#ifdef RTNL_CHECK
422  rtnl_entry_check(rtas, RTA_MAX + 1, ns_routemap, "route");
423#endif
424  route = ns_get_route(ns, rtm, rtas);
425
426  if (hdr->nlmsg_type == RTM_DELROUTE) {
427    if (!route)
428      return -1;
429    pool_put(ns->netns.routes, route);
430    netns_notify(ns, route, NETNS_TYPE_ROUTE, NETNS_F_DEL);
431    return 0;
432  }
433
434  if (!route) {
435    pool_get(ns->netns.routes, route);
436    memset(route, 0, sizeof(*route));
437    rtnl_entry_set(route, rtas, ns_routemap, 1);
438  } else {
439    rtnl_entry_set(route, rtas, ns_routemap, 0);
440  }
441
442  route->rtm = *rtm;
443  route->last_updated = vlib_time_now(vlib_get_main());
444  netns_notify(ns, route, NETNS_TYPE_ROUTE, NETNS_F_ADD);
445  return 0;
446}
447
448static ns_addr_t *
449ns_get_addr(netns_p *ns, struct ifaddrmsg *ifaddr, struct rtattr *rtas[])
450{
451  ns_addr_t *addr;
452
453  //This describes the values which uniquely identify a route
454  struct ifaddrmsg msg = {
455      .ifa_family = 0xff,
456      .ifa_prefixlen = 0xff,
457  };
458
459  pool_foreach(addr, ns->netns.addresses, {
460      if(mask_match(&addr->ifaddr, ifaddr, &msg, sizeof(struct ifaddrmsg)) &&
461          rtnl_entry_match(addr, rtas, ns_addrmap))
462        return addr;
463  });
464  return NULL;
465}
466
467static int
468ns_rcv_addr(netns_p *ns, struct nlmsghdr *hdr)
469{
470  ns_addr_t *addr;
471  struct ifaddrmsg *ifaddr;
472  struct rtattr *rtas[IFA_MAX + 1] = {};
473  size_t datalen = hdr->nlmsg_len - NLMSG_ALIGN(sizeof(*hdr));
474
475  if(datalen < sizeof(*ifaddr))
476    return -1;
477
478  ifaddr = NLMSG_DATA(hdr);
479  if((datalen > NLMSG_ALIGN(sizeof(*ifaddr))) &&
480      rtnl_parse_rtattr(rtas, IFA_MAX, IFA_RTA(ifaddr),
481                        IFA_PAYLOAD(hdr))) {
482    return -1;
483  }
484#ifdef RTNL_CHECK
485  rtnl_entry_check(rtas, IFA_MAX + 1, ns_addrmap, "addr");
486#endif
487  addr = ns_get_addr(ns, ifaddr, rtas);
488
489  if (hdr->nlmsg_type == RTM_DELADDR) {
490    if (!addr)
491      return -1;
492    pool_put(ns->netns.addresses, addr);
493    netns_notify(ns, addr, NETNS_TYPE_ADDR, NETNS_F_DEL);
494    return 0;
495  }
496
497  if (!addr) {
498    pool_get(ns->netns.addresses, addr);
499    memset(addr, 0, sizeof(*addr));
500    rtnl_entry_set(addr, rtas, ns_addrmap, 1);
501  } else {
502    rtnl_entry_set(addr, rtas, ns_addrmap, 0);
503  }
504
505  addr->ifaddr = *ifaddr;
506  addr->last_updated = vlib_time_now(vlib_get_main());
507  netns_notify(ns, addr, NETNS_TYPE_ADDR, NETNS_F_ADD);
508  return 0;
509}
510
511static ns_neigh_t *
512ns_get_neigh(netns_p *ns, struct ndmsg *nd, struct rtattr *rtas[])
513{
514  ns_neigh_t *neigh;
515
516  //This describes the values which uniquely identify a route
517  struct ndmsg msg = {
518      .ndm_family = 0xff,
519      .ndm_ifindex = 0xff,
520  };
521
522  pool_foreach(neigh, ns->netns.neighbors, {
523      if(mask_match(&neigh->nd, nd, &msg, sizeof(&msg)) &&
524          rtnl_entry_match(neigh, rtas, ns_neighmap))
525        return neigh;
526  });
527  return NULL;
528}
529
530static int
531ns_rcv_neigh(netns_p *ns, struct nlmsghdr *hdr)
532{
533  ns_neigh_t *neigh;
534  struct ndmsg *nd;
535  struct rtattr *rtas[NDA_MAX + 1] = {};
536  size_t datalen = hdr->nlmsg_len - NLMSG_ALIGN(sizeof(*hdr));
537
538  if(datalen < sizeof(*nd))
539    return -1;
540
541  nd = NLMSG_DATA(hdr);
542  if((datalen > NLMSG_ALIGN(sizeof(*nd))) &&
543      rtnl_parse_rtattr(rtas, NDA_MAX, NDA_RTA(nd),
544                        NDA_PAYLOAD(hdr))) {
545    return -1;
546  }
547#ifdef RTNL_CHECK
548  rtnl_entry_check(rtas, NDA_MAX + 1, ns_neighmap, "nd");
549#endif
550  neigh = ns_get_neigh(ns, nd, rtas);
551
552  if (hdr->nlmsg_type == RTM_DELNEIGH) {
553    if (!neigh)
554      return -1;
555    pool_put(ns->netns.neighbors, neigh);
556    netns_notify(ns, neigh, NETNS_TYPE_NEIGH, NETNS_F_DEL);
557    return 0;
558  }
559
560  if (!neigh) {
561    pool_get(ns->netns.neighbors, neigh);
562    memset(neigh, 0, sizeof(*neigh));
563    rtnl_entry_set(neigh, rtas, ns_neighmap, 1);
564  } else {
565    rtnl_entry_set(neigh, rtas, ns_neighmap, 0);
566  }
567
568  neigh->nd = *nd;
569  neigh->last_updated = vlib_time_now(vlib_get_main());
570  netns_notify(ns, neigh, NETNS_TYPE_NEIGH, NETNS_F_ADD);
571  return 0;
572}
573
574#define ns_object_foreach    \
575  _(neighbors, NETNS_TYPE_NEIGH) \
576  _(routes, NETNS_TYPE_ROUTE)    \
577  _(addresses, NETNS_TYPE_ADDR)  \
578  _(links, NETNS_TYPE_LINK)
579
580static void
581ns_recv_error(rtnl_error_t err, uword o)
582{
583  //An error was received. Reset everything.
584  netns_p *ns = &netns_main.netnss[o];
585  u32 *indexes = 0;
586  u32 *i = 0;
587
588#define _(pool, type) \
589  pool_foreach_index(*i, ns->netns.pool, {                   \
590      vec_add1(indexes, *i);                                 \
591  })                                                         \
592  vec_foreach(i, indexes) {                                  \
593    pool_put_index(ns->netns.pool, *i);                      \
594    netns_notify(ns, &ns->netns.pool[*i], type, NETNS_F_DEL);\
595  }                                                          \
596  vec_reset_length(indexes);
597
598  ns_object_foreach
599
600#undef _
601  vec_free(indexes);
602}
603
604static void
605ns_recv_rtnl(struct nlmsghdr *hdr, uword o)
606{
607  netns_p *ns = &netns_main.netnss[o];
608  switch (hdr->nlmsg_type) {
609    case RTM_NEWROUTE:
610    case RTM_DELROUTE:
611      ns_rcv_route(ns, hdr);
612      break;
613    case RTM_NEWLINK:
614    case RTM_DELLINK:
615      ns_rcv_link(ns, hdr);
616      break;
617    case RTM_NEWADDR:
618    case RTM_DELADDR:
619      ns_rcv_addr(ns, hdr);
620      break;
621    case RTM_NEWNEIGH:
622    case RTM_DELNEIGH:
623      ns_rcv_neigh(ns, hdr);
624      break;
625    default:
626      clib_warning("unknown rtnl type %d", hdr->nlmsg_type);
627      break;
628  }
629}
630
631static void
632netns_destroy(netns_p *ns)
633{
634  netns_main_t *nm = &netns_main;
635  rtnl_stream_close(ns->rtnl_handle);
636  pool_put(nm->netnss, ns);
637  pool_free(ns->netns.links);
638  pool_free(ns->netns.addresses);
639  pool_free(ns->netns.routes);
640  pool_free(ns->netns.neighbors);
641}
642
643static netns_p *
644netns_get(char *name)
645{
646  netns_main_t *nm = &netns_main;
647  netns_p *ns;
648  pool_foreach(ns, nm->netnss, {
649      if (!strcmp(name, ns->netns.name))
650        return ns;
651  });
652
653  if (strlen(name) > RTNL_NETNS_NAMELEN)
654    return NULL;
655
656  pool_get(nm->netnss, ns);
657  rtnl_stream_t s = {
658      .recv_message = ns_recv_rtnl,
659      .error = ns_recv_error,
660      .opaque = (uword)(ns - nm->netnss),
661  };
662  strcpy(s.name, name);
663
664  u32 handle;
665  if ((handle = rtnl_stream_open(&s)) == ~0) {
666    pool_put(nm->netnss, ns);
667    return NULL;
668  }
669
670  strcpy(ns->netns.name, name);
671  ns->netns.addresses = 0;
672  ns->netns.links = 0;
673  ns->netns.neighbors = 0;
674  ns->netns.routes = 0;
675  ns->subscriber_count = 0;
676  ns->rtnl_handle = handle;
677  return ns;
678}
679
680u32 netns_open(char *name, netns_sub_t *sub)
681{
682  netns_main_t *nm = &netns_main;
683  netns_p *ns;
684  netns_handle_t *p;
685  if (!(ns = netns_get(name)))
686    return ~0;
687
688  pool_get(nm->handles, p);
689  p->netns_index = ns - nm->netnss;
690  p->notify = sub->notify;
691  p->opaque = sub->opaque;
692  ns->subscriber_count++;
693  return p - nm->handles;
694}
695
696netns_t *netns_getns(u32 handle)
697{
698  netns_main_t *nm = &netns_main;
699  netns_handle_t *h = pool_elt_at_index(nm->handles, handle);
700  netns_p *ns = pool_elt_at_index(nm->netnss, h->netns_index);
701  return &ns->netns;
702}
703
704void netns_close(u32 handle)
705{
706  netns_main_t *nm = &netns_main;
707  netns_handle_t *h = pool_elt_at_index(nm->handles, handle);
708  netns_p *ns = pool_elt_at_index(nm->netnss, h->netns_index);
709  pool_put(h, nm->handles);
710  ns->subscriber_count--;
711  if (!ns->subscriber_count)
712    netns_destroy(ns);
713}
714
715void netns_callme(u32 handle, char del)
716{
717  netns_main_t *nm = &netns_main;
718  netns_handle_t *h = pool_elt_at_index(nm->handles, handle);
719  netns_p *ns = pool_elt_at_index(nm->netnss, h->netns_index);
720  u32 i = 0;
721  if (!h->notify)
722    return;
723
724#define _(pool, type) \
725  pool_foreach_index(i, ns->netns.pool, {                   \
726      h->notify(&ns->netns.pool[i], type,                   \
727      del?NETNS_F_DEL:NETNS_F_ADD, h->opaque);              \
728  });
729
730  ns_object_foreach
731#undef _
732
733}
734
735u8 *format_ns_object(u8 *s, va_list *args)
736{
737  netns_type_t t = va_arg(*args, netns_type_t);
738  void *o = va_arg(*args, void *);
739  switch (t) {
740    case NETNS_TYPE_ADDR:
741      return format(s, "addr %U", format_ns_addr, o);
742    case NETNS_TYPE_ROUTE:
743      return format(s, "route %U", format_ns_route, o);
744    case NETNS_TYPE_LINK:
745      return format(s, "link %U", format_ns_link, o);
746    case NETNS_TYPE_NEIGH:
747      return format(s, "neigh %U", format_ns_neigh, o);
748  }
749  return s;
750}
751
752u8 *format_ns_flags(u8 *s, va_list *args)
753{
754  u32 flags = va_arg(*args, u32);
755  if (flags & NETNS_F_ADD)
756    s = format(s, "add");
757  else if (flags & NETNS_F_DEL)
758    s = format(s, "del");
759  else
760    s = format(s, "mod");
761  return s;
762}
763
764clib_error_t *
765netns_init (vlib_main_t * vm)
766{
767  netns_main_t *nm = &netns_main;
768  nm->netnss = 0;
769  nm->handles = 0;
770  return 0;
771}
772
773VLIB_INIT_FUNCTION (netns_init);
774