00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151 #include <netlink-local.h>
00152 #include <netlink/netlink.h>
00153 #include <netlink/utils.h>
00154 #include <netlink/route/rtnl.h>
00155 #include <netlink/route/neighbour.h>
00156 #include <netlink/route/link.h>
00157
00158
00159 #define NEIGH_ATTR_FLAGS 0x01
00160 #define NEIGH_ATTR_STATE 0x02
00161 #define NEIGH_ATTR_LLADDR 0x04
00162 #define NEIGH_ATTR_DST 0x08
00163 #define NEIGH_ATTR_CACHEINFO 0x10
00164 #define NEIGH_ATTR_IFINDEX 0x20
00165 #define NEIGH_ATTR_FAMILY 0x40
00166 #define NEIGH_ATTR_TYPE 0x80
00167 #define NEIGH_ATTR_PROBES 0x100
00168
00169 static struct nl_cache_ops rtnl_neigh_ops;
00170 static struct nl_object_ops neigh_obj_ops;
00171
00172
00173 static void neigh_free_data(struct nl_object *c)
00174 {
00175 struct rtnl_neigh *neigh = nl_object_priv(c);
00176
00177 if (!neigh)
00178 return;
00179
00180 nl_addr_put(neigh->n_lladdr);
00181 nl_addr_put(neigh->n_dst);
00182 }
00183
00184 static int neigh_clone(struct nl_object *_dst, struct nl_object *_src)
00185 {
00186 struct rtnl_neigh *dst = nl_object_priv(_dst);
00187 struct rtnl_neigh *src = nl_object_priv(_src);
00188
00189 if (src->n_lladdr)
00190 if (!(dst->n_lladdr = nl_addr_clone(src->n_lladdr)))
00191 return -NLE_NOMEM;
00192
00193 if (src->n_dst)
00194 if (!(dst->n_dst = nl_addr_clone(src->n_dst)))
00195 return -NLE_NOMEM;
00196
00197 return 0;
00198 }
00199
00200 static int neigh_compare(struct nl_object *_a, struct nl_object *_b,
00201 uint32_t attrs, int flags)
00202 {
00203 struct rtnl_neigh *a = (struct rtnl_neigh *) _a;
00204 struct rtnl_neigh *b = (struct rtnl_neigh *) _b;
00205 int diff = 0;
00206
00207 #define NEIGH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGH_ATTR_##ATTR, a, b, EXPR)
00208
00209 diff |= NEIGH_DIFF(IFINDEX, a->n_ifindex != b->n_ifindex);
00210 diff |= NEIGH_DIFF(FAMILY, a->n_family != b->n_family);
00211 diff |= NEIGH_DIFF(TYPE, a->n_type != b->n_type);
00212 diff |= NEIGH_DIFF(LLADDR, nl_addr_cmp(a->n_lladdr, b->n_lladdr));
00213 diff |= NEIGH_DIFF(DST, nl_addr_cmp(a->n_dst, b->n_dst));
00214
00215 if (flags & LOOSE_COMPARISON) {
00216 diff |= NEIGH_DIFF(STATE,
00217 (a->n_state ^ b->n_state) & b->n_state_mask);
00218 diff |= NEIGH_DIFF(FLAGS,
00219 (a->n_flags ^ b->n_flags) & b->n_flag_mask);
00220 } else {
00221 diff |= NEIGH_DIFF(STATE, a->n_state != b->n_state);
00222 diff |= NEIGH_DIFF(FLAGS, a->n_flags != b->n_flags);
00223 }
00224
00225 #undef NEIGH_DIFF
00226
00227 return diff;
00228 }
00229
00230 static const struct trans_tbl neigh_attrs[] = {
00231 __ADD(NEIGH_ATTR_FLAGS, flags)
00232 __ADD(NEIGH_ATTR_STATE, state)
00233 __ADD(NEIGH_ATTR_LLADDR, lladdr)
00234 __ADD(NEIGH_ATTR_DST, dst)
00235 __ADD(NEIGH_ATTR_CACHEINFO, cacheinfo)
00236 __ADD(NEIGH_ATTR_IFINDEX, ifindex)
00237 __ADD(NEIGH_ATTR_FAMILY, family)
00238 __ADD(NEIGH_ATTR_TYPE, type)
00239 __ADD(NEIGH_ATTR_PROBES, probes)
00240 };
00241
00242 static char *neigh_attrs2str(int attrs, char *buf, size_t len)
00243 {
00244 return __flags2str(attrs, buf, len, neigh_attrs,
00245 ARRAY_SIZE(neigh_attrs));
00246 }
00247
00248 static struct nla_policy neigh_policy[NDA_MAX+1] = {
00249 [NDA_CACHEINFO] = { .minlen = sizeof(struct nda_cacheinfo) },
00250 [NDA_PROBES] = { .type = NLA_U32 },
00251 };
00252
00253 static int neigh_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00254 struct nlmsghdr *n, struct nl_parser_param *pp)
00255 {
00256 struct rtnl_neigh *neigh;
00257 struct nlattr *tb[NDA_MAX + 1];
00258 struct ndmsg *nm;
00259 int err;
00260
00261 neigh = rtnl_neigh_alloc();
00262 if (!neigh) {
00263 err = -NLE_NOMEM;
00264 goto errout;
00265 }
00266
00267 neigh->ce_msgtype = n->nlmsg_type;
00268 nm = nlmsg_data(n);
00269
00270 err = nlmsg_parse(n, sizeof(*nm), tb, NDA_MAX, neigh_policy);
00271 if (err < 0)
00272 goto errout;
00273
00274 neigh->n_family = nm->ndm_family;
00275 neigh->n_ifindex = nm->ndm_ifindex;
00276 neigh->n_state = nm->ndm_state;
00277 neigh->n_flags = nm->ndm_flags;
00278 neigh->n_type = nm->ndm_type;
00279
00280 neigh->ce_mask |= (NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX |
00281 NEIGH_ATTR_STATE | NEIGH_ATTR_FLAGS |
00282 NEIGH_ATTR_TYPE);
00283
00284 if (tb[NDA_LLADDR]) {
00285 neigh->n_lladdr = nl_addr_alloc_attr(tb[NDA_LLADDR], AF_UNSPEC);
00286 if (!neigh->n_lladdr) {
00287 err = -NLE_NOMEM;
00288 goto errout;
00289 }
00290 nl_addr_set_family(neigh->n_lladdr,
00291 nl_addr_guess_family(neigh->n_lladdr));
00292 neigh->ce_mask |= NEIGH_ATTR_LLADDR;
00293 }
00294
00295 if (tb[NDA_DST]) {
00296 neigh->n_dst = nl_addr_alloc_attr(tb[NDA_DST], neigh->n_family);
00297 if (!neigh->n_dst) {
00298 err = -NLE_NOMEM;
00299 goto errout;
00300 }
00301 neigh->ce_mask |= NEIGH_ATTR_DST;
00302 }
00303
00304 if (tb[NDA_CACHEINFO]) {
00305 struct nda_cacheinfo *ci = nla_data(tb[NDA_CACHEINFO]);
00306
00307 neigh->n_cacheinfo.nci_confirmed = ci->ndm_confirmed;
00308 neigh->n_cacheinfo.nci_used = ci->ndm_used;
00309 neigh->n_cacheinfo.nci_updated = ci->ndm_updated;
00310 neigh->n_cacheinfo.nci_refcnt = ci->ndm_refcnt;
00311
00312 neigh->ce_mask |= NEIGH_ATTR_CACHEINFO;
00313 }
00314
00315 if (tb[NDA_PROBES]) {
00316 neigh->n_probes = nla_get_u32(tb[NDA_PROBES]);
00317 neigh->ce_mask |= NEIGH_ATTR_PROBES;
00318 }
00319
00320 err = pp->pp_cb((struct nl_object *) neigh, pp);
00321 errout:
00322 rtnl_neigh_put(neigh);
00323 return err;
00324 }
00325
00326 static int neigh_request_update(struct nl_cache *c, struct nl_sock *h)
00327 {
00328 return nl_rtgen_request(h, RTM_GETNEIGH, AF_UNSPEC, NLM_F_DUMP);
00329 }
00330
00331
00332 static void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p)
00333 {
00334 char dst[INET6_ADDRSTRLEN+5], lladdr[INET6_ADDRSTRLEN+5];
00335 struct rtnl_neigh *n = (struct rtnl_neigh *) a;
00336 struct nl_cache *link_cache;
00337 char state[128], flags[64];
00338
00339 link_cache = nl_cache_mngt_require("route/link");
00340
00341 nl_dump_line(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst)));
00342
00343 if (link_cache)
00344 nl_dump(p, "dev %s ",
00345 rtnl_link_i2name(link_cache, n->n_ifindex,
00346 state, sizeof(state)));
00347 else
00348 nl_dump(p, "dev %d ", n->n_ifindex);
00349
00350 if (n->ce_mask & NEIGH_ATTR_LLADDR)
00351 nl_dump(p, "lladdr %s ",
00352 nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr)));
00353
00354 rtnl_neigh_state2str(n->n_state, state, sizeof(state));
00355 rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags));
00356
00357 if (state[0])
00358 nl_dump(p, "<%s", state);
00359 if (flags[0])
00360 nl_dump(p, "%s%s", state[0] ? "," : "<", flags);
00361 if (state[0] || flags[0])
00362 nl_dump(p, ">");
00363 nl_dump(p, "\n");
00364 }
00365
00366 static void neigh_dump_details(struct nl_object *a, struct nl_dump_params *p)
00367 {
00368 char rtn_type[32];
00369 struct rtnl_neigh *n = (struct rtnl_neigh *) a;
00370 int hz = nl_get_user_hz();
00371
00372 neigh_dump_line(a, p);
00373
00374 nl_dump_line(p, " refcnt %u type %s confirmed %u used "
00375 "%u updated %u\n",
00376 n->n_cacheinfo.nci_refcnt,
00377 nl_rtntype2str(n->n_type, rtn_type, sizeof(rtn_type)),
00378 n->n_cacheinfo.nci_confirmed/hz,
00379 n->n_cacheinfo.nci_used/hz, n->n_cacheinfo.nci_updated/hz);
00380 }
00381
00382 static void neigh_dump_stats(struct nl_object *a, struct nl_dump_params *p)
00383 {
00384 neigh_dump_details(a, p);
00385 }
00386
00387
00388
00389
00390
00391
00392 struct rtnl_neigh *rtnl_neigh_alloc(void)
00393 {
00394 return (struct rtnl_neigh *) nl_object_alloc(&neigh_obj_ops);
00395 }
00396
00397 void rtnl_neigh_put(struct rtnl_neigh *neigh)
00398 {
00399 nl_object_put((struct nl_object *) neigh);
00400 }
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 int rtnl_neigh_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
00420 {
00421 return nl_cache_alloc_and_fill(&rtnl_neigh_ops, sock, result);
00422 }
00423
00424
00425
00426
00427
00428
00429
00430
00431 struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex,
00432 struct nl_addr *dst)
00433 {
00434 struct rtnl_neigh *neigh;
00435
00436 nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
00437 if (neigh->n_ifindex == ifindex &&
00438 !nl_addr_cmp(neigh->n_dst, dst)) {
00439 nl_object_get((struct nl_object *) neigh);
00440 return neigh;
00441 }
00442 }
00443
00444 return NULL;
00445 }
00446
00447
00448
00449
00450
00451
00452
00453
00454 static int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags,
00455 struct nl_msg **result)
00456 {
00457 struct nl_msg *msg;
00458 struct ndmsg nhdr = {
00459 .ndm_ifindex = tmpl->n_ifindex,
00460 .ndm_state = NUD_PERMANENT,
00461 };
00462
00463 if (!(tmpl->ce_mask & NEIGH_ATTR_DST))
00464 return -NLE_MISSING_ATTR;
00465
00466 nhdr.ndm_family = nl_addr_get_family(tmpl->n_dst);
00467
00468 if (tmpl->ce_mask & NEIGH_ATTR_STATE)
00469 nhdr.ndm_state = tmpl->n_state;
00470
00471 msg = nlmsg_alloc_simple(cmd, flags);
00472 if (!msg)
00473 return -NLE_NOMEM;
00474
00475 if (nlmsg_append(msg, &nhdr, sizeof(nhdr), NLMSG_ALIGNTO) < 0)
00476 goto nla_put_failure;
00477
00478 NLA_PUT_ADDR(msg, NDA_DST, tmpl->n_dst);
00479
00480 if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
00481 NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr);
00482
00483 *result = msg;
00484 return 0;
00485
00486 nla_put_failure:
00487 nlmsg_free(msg);
00488 return -NLE_MSGSIZE;
00489 }
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511 int rtnl_neigh_build_add_request(struct rtnl_neigh *tmpl, int flags,
00512 struct nl_msg **result)
00513 {
00514 return build_neigh_msg(tmpl, RTM_NEWNEIGH, flags, result);
00515 }
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535 int rtnl_neigh_add(struct nl_sock *sk, struct rtnl_neigh *tmpl, int flags)
00536 {
00537 int err;
00538 struct nl_msg *msg;
00539
00540 if ((err = rtnl_neigh_build_add_request(tmpl, flags, &msg)) < 0)
00541 return err;
00542
00543 err = nl_send_auto_complete(sk, msg);
00544 nlmsg_free(msg);
00545 if (err < 0)
00546 return err;
00547
00548 return wait_for_ack(sk);
00549 }
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 int rtnl_neigh_build_delete_request(struct rtnl_neigh *neigh, int flags,
00573 struct nl_msg **result)
00574 {
00575 return build_neigh_msg(neigh, RTM_DELNEIGH, flags, result);
00576 }
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590 int rtnl_neigh_delete(struct nl_sock *sk, struct rtnl_neigh *neigh,
00591 int flags)
00592 {
00593 struct nl_msg *msg;
00594 int err;
00595
00596 if ((err = rtnl_neigh_build_delete_request(neigh, flags, &msg)) < 0)
00597 return err;
00598
00599 err = nl_send_auto_complete(sk, msg);
00600 nlmsg_free(msg);
00601 if (err < 0)
00602 return err;
00603
00604 return wait_for_ack(sk);
00605 }
00606
00607
00608
00609
00610
00611
00612
00613
00614 static const struct trans_tbl neigh_states[] = {
00615 __ADD(NUD_INCOMPLETE, incomplete)
00616 __ADD(NUD_REACHABLE, reachable)
00617 __ADD(NUD_STALE, stale)
00618 __ADD(NUD_DELAY, delay)
00619 __ADD(NUD_PROBE, probe)
00620 __ADD(NUD_FAILED, failed)
00621 __ADD(NUD_NOARP, norarp)
00622 __ADD(NUD_PERMANENT, permanent)
00623 };
00624
00625 char * rtnl_neigh_state2str(int state, char *buf, size_t len)
00626 {
00627 return __flags2str(state, buf, len, neigh_states,
00628 ARRAY_SIZE(neigh_states));
00629 }
00630
00631 int rtnl_neigh_str2state(const char *name)
00632 {
00633 return __str2type(name, neigh_states, ARRAY_SIZE(neigh_states));
00634 }
00635
00636
00637
00638
00639
00640
00641
00642
00643 static const struct trans_tbl neigh_flags[] = {
00644 __ADD(NTF_USE, use)
00645 __ADD(NTF_PROXY, proxy)
00646 __ADD(NTF_ROUTER, router)
00647 };
00648
00649 char * rtnl_neigh_flags2str(int flags, char *buf, size_t len)
00650 {
00651 return __flags2str(flags, buf, len, neigh_flags,
00652 ARRAY_SIZE(neigh_flags));
00653 }
00654
00655 int rtnl_neigh_str2flag(const char *name)
00656 {
00657 return __str2type(name, neigh_flags, ARRAY_SIZE(neigh_flags));
00658 }
00659
00660
00661
00662
00663
00664
00665
00666
00667 void rtnl_neigh_set_state(struct rtnl_neigh *neigh, int state)
00668 {
00669 neigh->n_state_mask |= state;
00670 neigh->n_state |= state;
00671 neigh->ce_mask |= NEIGH_ATTR_STATE;
00672 }
00673
00674 int rtnl_neigh_get_state(struct rtnl_neigh *neigh)
00675 {
00676 if (neigh->ce_mask & NEIGH_ATTR_STATE)
00677 return neigh->n_state;
00678 else
00679 return -1;
00680 }
00681
00682 void rtnl_neigh_unset_state(struct rtnl_neigh *neigh, int state)
00683 {
00684 neigh->n_state_mask |= state;
00685 neigh->n_state &= ~state;
00686 neigh->ce_mask |= NEIGH_ATTR_STATE;
00687 }
00688
00689 void rtnl_neigh_set_flags(struct rtnl_neigh *neigh, unsigned int flags)
00690 {
00691 neigh->n_flag_mask |= flags;
00692 neigh->n_flags |= flags;
00693 neigh->ce_mask |= NEIGH_ATTR_FLAGS;
00694 }
00695
00696 unsigned int rtnl_neigh_get_flags(struct rtnl_neigh *neigh)
00697 {
00698 return neigh->n_flags;
00699 }
00700
00701 void rtnl_neigh_unset_flags(struct rtnl_neigh *neigh, unsigned int flags)
00702 {
00703 neigh->n_flag_mask |= flags;
00704 neigh->n_flags &= ~flags;
00705 neigh->ce_mask |= NEIGH_ATTR_FLAGS;
00706 }
00707
00708 void rtnl_neigh_set_ifindex(struct rtnl_neigh *neigh, int ifindex)
00709 {
00710 neigh->n_ifindex = ifindex;
00711 neigh->ce_mask |= NEIGH_ATTR_IFINDEX;
00712 }
00713
00714 int rtnl_neigh_get_ifindex(struct rtnl_neigh *neigh)
00715 {
00716 return neigh->n_ifindex;
00717 }
00718
00719 static inline int __assign_addr(struct rtnl_neigh *neigh, struct nl_addr **pos,
00720 struct nl_addr *new, int flag, int nocheck)
00721 {
00722 if (!nocheck) {
00723 if (neigh->ce_mask & NEIGH_ATTR_FAMILY) {
00724 if (new->a_family != neigh->n_family)
00725 return -NLE_AF_MISMATCH;
00726 } else {
00727 neigh->n_family = new->a_family;
00728 neigh->ce_mask |= NEIGH_ATTR_FAMILY;
00729 }
00730 }
00731
00732 if (*pos)
00733 nl_addr_put(*pos);
00734
00735 nl_addr_get(new);
00736 *pos = new;
00737
00738 neigh->ce_mask |= flag;
00739
00740 return 0;
00741 }
00742
00743 void rtnl_neigh_set_lladdr(struct rtnl_neigh *neigh, struct nl_addr *addr)
00744 {
00745 __assign_addr(neigh, &neigh->n_lladdr, addr, NEIGH_ATTR_LLADDR, 1);
00746 }
00747
00748 struct nl_addr *rtnl_neigh_get_lladdr(struct rtnl_neigh *neigh)
00749 {
00750 if (neigh->ce_mask & NEIGH_ATTR_LLADDR)
00751 return neigh->n_lladdr;
00752 else
00753 return NULL;
00754 }
00755
00756 int rtnl_neigh_set_dst(struct rtnl_neigh *neigh, struct nl_addr *addr)
00757 {
00758 return __assign_addr(neigh, &neigh->n_dst, addr,
00759 NEIGH_ATTR_DST, 0);
00760 }
00761
00762 struct nl_addr *rtnl_neigh_get_dst(struct rtnl_neigh *neigh)
00763 {
00764 if (neigh->ce_mask & NEIGH_ATTR_DST)
00765 return neigh->n_dst;
00766 else
00767 return NULL;
00768 }
00769
00770 void rtnl_neigh_set_family(struct rtnl_neigh *neigh, int family)
00771 {
00772 neigh->n_family = family;
00773 neigh->ce_mask |= NEIGH_ATTR_FAMILY;
00774 }
00775
00776 int rtnl_neigh_get_family(struct rtnl_neigh *neigh)
00777 {
00778 return neigh->n_family;
00779 }
00780
00781 void rtnl_neigh_set_type(struct rtnl_neigh *neigh, int type)
00782 {
00783 neigh->n_type = type;
00784 neigh->ce_mask = NEIGH_ATTR_TYPE;
00785 }
00786
00787 int rtnl_neigh_get_type(struct rtnl_neigh *neigh)
00788 {
00789 if (neigh->ce_mask & NEIGH_ATTR_TYPE)
00790 return neigh->n_type;
00791 else
00792 return -1;
00793 }
00794
00795
00796
00797 static struct nl_object_ops neigh_obj_ops = {
00798 .oo_name = "route/neigh",
00799 .oo_size = sizeof(struct rtnl_neigh),
00800 .oo_free_data = neigh_free_data,
00801 .oo_clone = neigh_clone,
00802 .oo_dump = {
00803 [NL_DUMP_LINE] = neigh_dump_line,
00804 [NL_DUMP_DETAILS] = neigh_dump_details,
00805 [NL_DUMP_STATS] = neigh_dump_stats,
00806 },
00807 .oo_compare = neigh_compare,
00808 .oo_attrs2str = neigh_attrs2str,
00809 .oo_id_attrs = (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY),
00810 };
00811
00812 static struct nl_af_group neigh_groups[] = {
00813 { AF_UNSPEC, RTNLGRP_NEIGH },
00814 { END_OF_GROUP_LIST },
00815 };
00816
00817 static struct nl_cache_ops rtnl_neigh_ops = {
00818 .co_name = "route/neigh",
00819 .co_hdrsize = sizeof(struct ndmsg),
00820 .co_msgtypes = {
00821 { RTM_NEWNEIGH, NL_ACT_NEW, "new" },
00822 { RTM_DELNEIGH, NL_ACT_DEL, "del" },
00823 { RTM_GETNEIGH, NL_ACT_GET, "get" },
00824 END_OF_MSGTYPES_LIST,
00825 },
00826 .co_protocol = NETLINK_ROUTE,
00827 .co_groups = neigh_groups,
00828 .co_request_update = neigh_request_update,
00829 .co_msg_parser = neigh_msg_parser,
00830 .co_obj_ops = &neigh_obj_ops,
00831 };
00832
00833 static void __init neigh_init(void)
00834 {
00835 nl_cache_mngt_register(&rtnl_neigh_ops);
00836 }
00837
00838 static void __exit neigh_exit(void)
00839 {
00840 nl_cache_mngt_unregister(&rtnl_neigh_ops);
00841 }
00842
00843