~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/ila/ila_xlat.c

Version: ~ [ linux-5.13-rc2 ] ~ [ linux-5.12.4 ] ~ [ linux-5.11.21 ] ~ [ linux-5.10.37 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.119 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.190 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.232 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.268 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.268 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 #include <linux/jhash.h>
  2 #include <linux/netfilter.h>
  3 #include <linux/rcupdate.h>
  4 #include <linux/rhashtable.h>
  5 #include <linux/vmalloc.h>
  6 #include <net/genetlink.h>
  7 #include <net/ila.h>
  8 #include <net/netns/generic.h>
  9 #include <uapi/linux/genetlink.h>
 10 #include "ila.h"
 11 
 12 struct ila_xlat_params {
 13         struct ila_params ip;
 14         __be64 identifier;
 15         int ifindex;
 16         unsigned int dir;
 17 };
 18 
 19 struct ila_map {
 20         struct ila_xlat_params p;
 21         struct rhash_head node;
 22         struct ila_map __rcu *next;
 23         struct rcu_head rcu;
 24 };
 25 
 26 static unsigned int ila_net_id;
 27 
 28 struct ila_net {
 29         struct rhashtable rhash_table;
 30         spinlock_t *locks; /* Bucket locks for entry manipulation */
 31         unsigned int locks_mask;
 32         bool hooks_registered;
 33 };
 34 
 35 #define LOCKS_PER_CPU 10
 36 
 37 static int alloc_ila_locks(struct ila_net *ilan)
 38 {
 39         unsigned int i, size;
 40         unsigned int nr_pcpus = num_possible_cpus();
 41 
 42         nr_pcpus = min_t(unsigned int, nr_pcpus, 32UL);
 43         size = roundup_pow_of_two(nr_pcpus * LOCKS_PER_CPU);
 44 
 45         if (sizeof(spinlock_t) != 0) {
 46 #ifdef CONFIG_NUMA
 47                 if (size * sizeof(spinlock_t) > PAGE_SIZE)
 48                         ilan->locks = vmalloc(size * sizeof(spinlock_t));
 49                 else
 50 #endif
 51                 ilan->locks = kmalloc_array(size, sizeof(spinlock_t),
 52                                             GFP_KERNEL);
 53                 if (!ilan->locks)
 54                         return -ENOMEM;
 55                 for (i = 0; i < size; i++)
 56                         spin_lock_init(&ilan->locks[i]);
 57         }
 58         ilan->locks_mask = size - 1;
 59 
 60         return 0;
 61 }
 62 
 63 static u32 hashrnd __read_mostly;
 64 static __always_inline void __ila_hash_secret_init(void)
 65 {
 66         net_get_random_once(&hashrnd, sizeof(hashrnd));
 67 }
 68 
 69 static inline u32 ila_identifier_hash(__be64 identifier)
 70 {
 71         u32 *v = (u32 *)&identifier;
 72 
 73         return jhash_2words(v[0], v[1], hashrnd);
 74 }
 75 
 76 static inline spinlock_t *ila_get_lock(struct ila_net *ilan, __be64 identifier)
 77 {
 78         return &ilan->locks[ila_identifier_hash(identifier) & ilan->locks_mask];
 79 }
 80 
 81 static inline int ila_cmp_wildcards(struct ila_map *ila, __be64 loc,
 82                                     int ifindex, unsigned int dir)
 83 {
 84         return (ila->p.ip.locator_match && ila->p.ip.locator_match != loc) ||
 85                (ila->p.ifindex && ila->p.ifindex != ifindex) ||
 86                !(ila->p.dir & dir);
 87 }
 88 
 89 static inline int ila_cmp_params(struct ila_map *ila, struct ila_xlat_params *p)
 90 {
 91         return (ila->p.ip.locator_match != p->ip.locator_match) ||
 92                (ila->p.ifindex != p->ifindex) ||
 93                (ila->p.dir != p->dir);
 94 }
 95 
 96 static int ila_cmpfn(struct rhashtable_compare_arg *arg,
 97                      const void *obj)
 98 {
 99         const struct ila_map *ila = obj;
100 
101         return (ila->p.identifier != *(__be64 *)arg->key);
102 }
103 
104 static inline int ila_order(struct ila_map *ila)
105 {
106         int score = 0;
107 
108         if (ila->p.ip.locator_match)
109                 score += 1 << 0;
110 
111         if (ila->p.ifindex)
112                 score += 1 << 1;
113 
114         return score;
115 }
116 
117 static const struct rhashtable_params rht_params = {
118         .nelem_hint = 1024,
119         .head_offset = offsetof(struct ila_map, node),
120         .key_offset = offsetof(struct ila_map, p.identifier),
121         .key_len = sizeof(u64), /* identifier */
122         .max_size = 1048576,
123         .min_size = 256,
124         .automatic_shrinking = true,
125         .obj_cmpfn = ila_cmpfn,
126 };
127 
128 static struct genl_family ila_nl_family = {
129         .id             = GENL_ID_GENERATE,
130         .hdrsize        = 0,
131         .name           = ILA_GENL_NAME,
132         .version        = ILA_GENL_VERSION,
133         .maxattr        = ILA_ATTR_MAX,
134         .netnsok        = true,
135         .parallel_ops   = true,
136 };
137 
138 static struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = {
139         [ILA_ATTR_IDENTIFIER] = { .type = NLA_U64, },
140         [ILA_ATTR_LOCATOR] = { .type = NLA_U64, },
141         [ILA_ATTR_LOCATOR_MATCH] = { .type = NLA_U64, },
142         [ILA_ATTR_IFINDEX] = { .type = NLA_U32, },
143         [ILA_ATTR_DIR] = { .type = NLA_U32, },
144 };
145 
146 static int parse_nl_config(struct genl_info *info,
147                            struct ila_xlat_params *p)
148 {
149         memset(p, 0, sizeof(*p));
150 
151         if (info->attrs[ILA_ATTR_IDENTIFIER])
152                 p->identifier = (__force __be64)nla_get_u64(
153                         info->attrs[ILA_ATTR_IDENTIFIER]);
154 
155         if (info->attrs[ILA_ATTR_LOCATOR])
156                 p->ip.locator = (__force __be64)nla_get_u64(
157                         info->attrs[ILA_ATTR_LOCATOR]);
158 
159         if (info->attrs[ILA_ATTR_LOCATOR_MATCH])
160                 p->ip.locator_match = (__force __be64)nla_get_u64(
161                         info->attrs[ILA_ATTR_LOCATOR_MATCH]);
162 
163         if (info->attrs[ILA_ATTR_IFINDEX])
164                 p->ifindex = nla_get_s32(info->attrs[ILA_ATTR_IFINDEX]);
165 
166         if (info->attrs[ILA_ATTR_DIR])
167                 p->dir = nla_get_u32(info->attrs[ILA_ATTR_DIR]);
168 
169         return 0;
170 }
171 
172 /* Must be called with rcu readlock */
173 static inline struct ila_map *ila_lookup_wildcards(__be64 id, __be64 loc,
174                                                    int ifindex,
175                                                    unsigned int dir,
176                                                    struct ila_net *ilan)
177 {
178         struct ila_map *ila;
179 
180         ila = rhashtable_lookup_fast(&ilan->rhash_table, &id, rht_params);
181         while (ila) {
182                 if (!ila_cmp_wildcards(ila, loc, ifindex, dir))
183                         return ila;
184                 ila = rcu_access_pointer(ila->next);
185         }
186 
187         return NULL;
188 }
189 
190 /* Must be called with rcu readlock */
191 static inline struct ila_map *ila_lookup_by_params(struct ila_xlat_params *p,
192                                                    struct ila_net *ilan)
193 {
194         struct ila_map *ila;
195 
196         ila = rhashtable_lookup_fast(&ilan->rhash_table, &p->identifier,
197                                      rht_params);
198         while (ila) {
199                 if (!ila_cmp_params(ila, p))
200                         return ila;
201                 ila = rcu_access_pointer(ila->next);
202         }
203 
204         return NULL;
205 }
206 
207 static inline void ila_release(struct ila_map *ila)
208 {
209         kfree_rcu(ila, rcu);
210 }
211 
212 static void ila_free_cb(void *ptr, void *arg)
213 {
214         struct ila_map *ila = (struct ila_map *)ptr, *next;
215 
216         /* Assume rcu_readlock held */
217         while (ila) {
218                 next = rcu_access_pointer(ila->next);
219                 ila_release(ila);
220                 ila = next;
221         }
222 }
223 
224 static int ila_xlat_addr(struct sk_buff *skb, int dir);
225 
226 static unsigned int
227 ila_nf_input(void *priv,
228              struct sk_buff *skb,
229              const struct nf_hook_state *state)
230 {
231         ila_xlat_addr(skb, ILA_DIR_IN);
232         return NF_ACCEPT;
233 }
234 
235 static struct nf_hook_ops ila_nf_hook_ops[] __read_mostly = {
236         {
237                 .hook = ila_nf_input,
238                 .pf = NFPROTO_IPV6,
239                 .hooknum = NF_INET_PRE_ROUTING,
240                 .priority = -1,
241         },
242 };
243 
244 static int ila_add_mapping(struct net *net, struct ila_xlat_params *p)
245 {
246         struct ila_net *ilan = net_generic(net, ila_net_id);
247         struct ila_map *ila, *head;
248         spinlock_t *lock = ila_get_lock(ilan, p->identifier);
249         int err = 0, order;
250 
251         if (!ilan->hooks_registered) {
252                 /* We defer registering net hooks in the namespace until the
253                  * first mapping is added.
254                  */
255                 err = nf_register_net_hooks(net, ila_nf_hook_ops,
256                                             ARRAY_SIZE(ila_nf_hook_ops));
257                 if (err)
258                         return err;
259 
260                 ilan->hooks_registered = true;
261         }
262 
263         ila = kzalloc(sizeof(*ila), GFP_KERNEL);
264         if (!ila)
265                 return -ENOMEM;
266 
267         ila->p = *p;
268 
269         if (p->ip.locator_match) {
270                 /* Precompute checksum difference for translation since we
271                  * know both the old identifier and the new one.
272                  */
273                 ila->p.ip.csum_diff = compute_csum_diff8(
274                         (__be32 *)&p->ip.locator_match,
275                         (__be32 *)&p->ip.locator);
276         }
277 
278         order = ila_order(ila);
279 
280         spin_lock(lock);
281 
282         head = rhashtable_lookup_fast(&ilan->rhash_table, &p->identifier,
283                                       rht_params);
284         if (!head) {
285                 /* New entry for the rhash_table */
286                 err = rhashtable_lookup_insert_fast(&ilan->rhash_table,
287                                                     &ila->node, rht_params);
288         } else {
289                 struct ila_map *tila = head, *prev = NULL;
290 
291                 do {
292                         if (!ila_cmp_params(tila, p)) {
293                                 err = -EEXIST;
294                                 goto out;
295                         }
296 
297                         if (order > ila_order(tila))
298                                 break;
299 
300                         prev = tila;
301                         tila = rcu_dereference_protected(tila->next,
302                                 lockdep_is_held(lock));
303                 } while (tila);
304 
305                 if (prev) {
306                         /* Insert in sub list of head */
307                         RCU_INIT_POINTER(ila->next, tila);
308                         rcu_assign_pointer(prev->next, ila);
309                 } else {
310                         /* Make this ila new head */
311                         RCU_INIT_POINTER(ila->next, head);
312                         err = rhashtable_replace_fast(&ilan->rhash_table,
313                                                       &head->node,
314                                                       &ila->node, rht_params);
315                         if (err)
316                                 goto out;
317                 }
318         }
319 
320 out:
321         spin_unlock(lock);
322 
323         if (err)
324                 kfree(ila);
325 
326         return err;
327 }
328 
329 static int ila_del_mapping(struct net *net, struct ila_xlat_params *p)
330 {
331         struct ila_net *ilan = net_generic(net, ila_net_id);
332         struct ila_map *ila, *head, *prev;
333         spinlock_t *lock = ila_get_lock(ilan, p->identifier);
334         int err = -ENOENT;
335 
336         spin_lock(lock);
337 
338         head = rhashtable_lookup_fast(&ilan->rhash_table,
339                                       &p->identifier, rht_params);
340         ila = head;
341 
342         prev = NULL;
343 
344         while (ila) {
345                 if (ila_cmp_params(ila, p)) {
346                         prev = ila;
347                         ila = rcu_dereference_protected(ila->next,
348                                                         lockdep_is_held(lock));
349                         continue;
350                 }
351 
352                 err = 0;
353 
354                 if (prev) {
355                         /* Not head, just delete from list */
356                         rcu_assign_pointer(prev->next, ila->next);
357                 } else {
358                         /* It is the head. If there is something in the
359                          * sublist we need to make a new head.
360                          */
361                         head = rcu_dereference_protected(ila->next,
362                                                          lockdep_is_held(lock));
363                         if (head) {
364                                 /* Put first entry in the sublist into the
365                                  * table
366                                  */
367                                 err = rhashtable_replace_fast(
368                                         &ilan->rhash_table, &ila->node,
369                                         &head->node, rht_params);
370                                 if (err)
371                                         goto out;
372                         } else {
373                                 /* Entry no longer used */
374                                 err = rhashtable_remove_fast(&ilan->rhash_table,
375                                                              &ila->node,
376                                                              rht_params);
377                         }
378                 }
379 
380                 ila_release(ila);
381 
382                 break;
383         }
384 
385 out:
386         spin_unlock(lock);
387 
388         return err;
389 }
390 
391 static int ila_nl_cmd_add_mapping(struct sk_buff *skb, struct genl_info *info)
392 {
393         struct net *net = genl_info_net(info);
394         struct ila_xlat_params p;
395         int err;
396 
397         err = parse_nl_config(info, &p);
398         if (err)
399                 return err;
400 
401         return ila_add_mapping(net, &p);
402 }
403 
404 static int ila_nl_cmd_del_mapping(struct sk_buff *skb, struct genl_info *info)
405 {
406         struct net *net = genl_info_net(info);
407         struct ila_xlat_params p;
408         int err;
409 
410         err = parse_nl_config(info, &p);
411         if (err)
412                 return err;
413 
414         ila_del_mapping(net, &p);
415 
416         return 0;
417 }
418 
419 static int ila_fill_info(struct ila_map *ila, struct sk_buff *msg)
420 {
421         if (nla_put_u64(msg, ILA_ATTR_IDENTIFIER,
422                         (__force u64)ila->p.identifier) ||
423             nla_put_u64(msg, ILA_ATTR_LOCATOR,
424                         (__force u64)ila->p.ip.locator) ||
425             nla_put_u64(msg, ILA_ATTR_LOCATOR_MATCH,
426                         (__force u64)ila->p.ip.locator_match) ||
427             nla_put_s32(msg, ILA_ATTR_IFINDEX, ila->p.ifindex) ||
428             nla_put_u32(msg, ILA_ATTR_DIR, ila->p.dir))
429                 return -1;
430 
431         return 0;
432 }
433 
434 static int ila_dump_info(struct ila_map *ila,
435                          u32 portid, u32 seq, u32 flags,
436                          struct sk_buff *skb, u8 cmd)
437 {
438         void *hdr;
439 
440         hdr = genlmsg_put(skb, portid, seq, &ila_nl_family, flags, cmd);
441         if (!hdr)
442                 return -ENOMEM;
443 
444         if (ila_fill_info(ila, skb) < 0)
445                 goto nla_put_failure;
446 
447         genlmsg_end(skb, hdr);
448         return 0;
449 
450 nla_put_failure:
451         genlmsg_cancel(skb, hdr);
452         return -EMSGSIZE;
453 }
454 
455 static int ila_nl_cmd_get_mapping(struct sk_buff *skb, struct genl_info *info)
456 {
457         struct net *net = genl_info_net(info);
458         struct ila_net *ilan = net_generic(net, ila_net_id);
459         struct sk_buff *msg;
460         struct ila_xlat_params p;
461         struct ila_map *ila;
462         int ret;
463 
464         ret = parse_nl_config(info, &p);
465         if (ret)
466                 return ret;
467 
468         msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
469         if (!msg)
470                 return -ENOMEM;
471 
472         rcu_read_lock();
473 
474         ila = ila_lookup_by_params(&p, ilan);
475         if (ila) {
476                 ret = ila_dump_info(ila,
477                                     info->snd_portid,
478                                     info->snd_seq, 0, msg,
479                                     info->genlhdr->cmd);
480         }
481 
482         rcu_read_unlock();
483 
484         if (ret < 0)
485                 goto out_free;
486 
487         return genlmsg_reply(msg, info);
488 
489 out_free:
490         nlmsg_free(msg);
491         return ret;
492 }
493 
494 struct ila_dump_iter {
495         struct rhashtable_iter rhiter;
496 };
497 
498 static int ila_nl_dump_start(struct netlink_callback *cb)
499 {
500         struct net *net = sock_net(cb->skb->sk);
501         struct ila_net *ilan = net_generic(net, ila_net_id);
502         struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args;
503 
504         return rhashtable_walk_init(&ilan->rhash_table, &iter->rhiter);
505 }
506 
507 static int ila_nl_dump_done(struct netlink_callback *cb)
508 {
509         struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args;
510 
511         rhashtable_walk_exit(&iter->rhiter);
512 
513         return 0;
514 }
515 
516 static int ila_nl_dump(struct sk_buff *skb, struct netlink_callback *cb)
517 {
518         struct ila_dump_iter *iter = (struct ila_dump_iter *)cb->args;
519         struct rhashtable_iter *rhiter = &iter->rhiter;
520         struct ila_map *ila;
521         int ret;
522 
523         ret = rhashtable_walk_start(rhiter);
524         if (ret && ret != -EAGAIN)
525                 goto done;
526 
527         for (;;) {
528                 ila = rhashtable_walk_next(rhiter);
529 
530                 if (IS_ERR(ila)) {
531                         if (PTR_ERR(ila) == -EAGAIN)
532                                 continue;
533                         ret = PTR_ERR(ila);
534                         goto done;
535                 } else if (!ila) {
536                         break;
537                 }
538 
539                 while (ila) {
540                         ret =  ila_dump_info(ila, NETLINK_CB(cb->skb).portid,
541                                              cb->nlh->nlmsg_seq, NLM_F_MULTI,
542                                              skb, ILA_CMD_GET);
543                         if (ret)
544                                 goto done;
545 
546                         ila = rcu_access_pointer(ila->next);
547                 }
548         }
549 
550         ret = skb->len;
551 
552 done:
553         rhashtable_walk_stop(rhiter);
554         return ret;
555 }
556 
557 static const struct genl_ops ila_nl_ops[] = {
558         {
559                 .cmd = ILA_CMD_ADD,
560                 .doit = ila_nl_cmd_add_mapping,
561                 .policy = ila_nl_policy,
562                 .flags = GENL_ADMIN_PERM,
563         },
564         {
565                 .cmd = ILA_CMD_DEL,
566                 .doit = ila_nl_cmd_del_mapping,
567                 .policy = ila_nl_policy,
568                 .flags = GENL_ADMIN_PERM,
569         },
570         {
571                 .cmd = ILA_CMD_GET,
572                 .doit = ila_nl_cmd_get_mapping,
573                 .start = ila_nl_dump_start,
574                 .dumpit = ila_nl_dump,
575                 .done = ila_nl_dump_done,
576                 .policy = ila_nl_policy,
577         },
578 };
579 
580 #define ILA_HASH_TABLE_SIZE 1024
581 
582 static __net_init int ila_init_net(struct net *net)
583 {
584         int err;
585         struct ila_net *ilan = net_generic(net, ila_net_id);
586 
587         err = alloc_ila_locks(ilan);
588         if (err)
589                 return err;
590 
591         rhashtable_init(&ilan->rhash_table, &rht_params);
592 
593         return 0;
594 }
595 
596 static __net_exit void ila_exit_net(struct net *net)
597 {
598         struct ila_net *ilan = net_generic(net, ila_net_id);
599 
600         rhashtable_free_and_destroy(&ilan->rhash_table, ila_free_cb, NULL);
601 
602         kvfree(ilan->locks);
603 
604         if (ilan->hooks_registered)
605                 nf_unregister_net_hooks(net, ila_nf_hook_ops,
606                                         ARRAY_SIZE(ila_nf_hook_ops));
607 }
608 
609 static struct pernet_operations ila_net_ops = {
610         .init = ila_init_net,
611         .exit = ila_exit_net,
612         .id   = &ila_net_id,
613         .size = sizeof(struct ila_net),
614 };
615 
616 static int ila_xlat_addr(struct sk_buff *skb, int dir)
617 {
618         struct ila_map *ila;
619         struct ipv6hdr *ip6h = ipv6_hdr(skb);
620         struct net *net = dev_net(skb->dev);
621         struct ila_net *ilan = net_generic(net, ila_net_id);
622         __be64 identifier, locator_match;
623         size_t nhoff;
624 
625         /* Assumes skb contains a valid IPv6 header that is pulled */
626 
627         identifier = *(__be64 *)&ip6h->daddr.in6_u.u6_addr8[8];
628         locator_match = *(__be64 *)&ip6h->daddr.in6_u.u6_addr8[0];
629         nhoff = sizeof(struct ipv6hdr);
630 
631         rcu_read_lock();
632 
633         ila = ila_lookup_wildcards(identifier, locator_match,
634                                    skb->dev->ifindex, dir, ilan);
635         if (ila)
636                 update_ipv6_locator(skb, &ila->p.ip);
637 
638         rcu_read_unlock();
639 
640         return 0;
641 }
642 
643 int ila_xlat_incoming(struct sk_buff *skb)
644 {
645         return ila_xlat_addr(skb, ILA_DIR_IN);
646 }
647 EXPORT_SYMBOL(ila_xlat_incoming);
648 
649 int ila_xlat_outgoing(struct sk_buff *skb)
650 {
651         return ila_xlat_addr(skb, ILA_DIR_OUT);
652 }
653 EXPORT_SYMBOL(ila_xlat_outgoing);
654 
655 int ila_xlat_init(void)
656 {
657         int ret;
658 
659         ret = register_pernet_device(&ila_net_ops);
660         if (ret)
661                 goto exit;
662 
663         ret = genl_register_family_with_ops(&ila_nl_family,
664                                             ila_nl_ops);
665         if (ret < 0)
666                 goto unregister;
667 
668         return 0;
669 
670 unregister:
671         unregister_pernet_device(&ila_net_ops);
672 exit:
673         return ret;
674 }
675 
676 void ila_xlat_fini(void)
677 {
678         genl_unregister_family(&ila_nl_family);
679         unregister_pernet_device(&ila_net_ops);
680 }
681 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp