Change NHLFE MTU calculation
[mpls-linux.git] / src / mpls_netlink.c
blobb5ba37d197333f6db35a8dabf1f1778dc8c74ee6
1 /*****************************************************************************
2 * MPLS
3 * An implementation of the MPLS (MultiProtocol Label
4 * Switching) Architecture for Linux.
6 * NetLink Interface for MPLS subsystem
8 * Authors:
9 * Ramon Casellas <casellas@infres.enst.fr>
11 * (c) 1999-2005 James Leu <jleu@mindspring.com>
12 * (c) 2003-2004 Ramon Casellas <casellas@infres.enst.fr>
14 * 20051116 - jleu - convert to genetlink
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version
19 * 2 of the License, or (at your option) any later version.
21 *****************************************************************************/
23 #include <linux/autoconf.h>
24 #include <linux/netdevice.h>
25 #include <net/arp.h>
26 #include <net/sock.h>
27 #include <net/mpls.h>
28 #include <linux/netlink.h>
29 #include <net/genetlink.h>
30 #include <linux/gen_stats.h>
31 #include <net/net_namespace.h>
33 extern struct list_head mpls_ilm_list;
34 extern struct list_head mpls_nhlfe_list;
36 static struct genl_family genl_mpls = {
37 .id = PF_MPLS,
38 .name = "nlmpls",
39 .version = 0x1,
40 .maxattr = MPLS_ATTR_MAX,
43 /* ILM netlink support */
45 static int mpls_fill_ilm(struct sk_buff *skb, struct mpls_ilm *ilm,
46 u32 pid, u32 seq, int flag, int event)
48 struct mpls_in_label_req mil;
49 struct gnet_stats_basic stats;
50 struct mpls_instr_req *instr;
51 void *hdr;
53 MPLS_ENTER;
55 hdr = genlmsg_put(skb, pid, seq, &genl_mpls, flag, event);
57 instr = kmalloc(sizeof(*instr), GFP_KERNEL);
58 if (unlikely(!instr))
59 goto nla_put_failure;
61 mil.mil_proto = ilm->ilm_proto->family;
62 memcpy(&mil.mil_label, &ilm->ilm_label, sizeof (struct mpls_label));
63 mpls_instrs_unbuild(ilm->ilm_instr, instr);
64 instr->mir_direction = MPLS_IN;
65 memcpy(&stats, &ilm->ilm_stats, sizeof(stats));
66 /* need to add drops here some how */
68 NLA_PUT(skb, MPLS_ATTR_ILM, sizeof(mil), &mil);
69 NLA_PUT(skb, MPLS_ATTR_INSTR, sizeof(*instr), instr);
70 NLA_PUT(skb, MPLS_ATTR_STATS, sizeof(stats), &stats);
72 kfree(instr);
74 MPLS_EXIT;
75 return genlmsg_end(skb, hdr);
77 nla_put_failure:
78 if (instr)
79 kfree(instr);
80 genlmsg_cancel(skb, hdr);
81 MPLS_DEBUG("Exit: -1\n");
82 return -ENOMEM;
85 void mpls_ilm_event(int event, struct mpls_ilm *ilm)
87 struct sk_buff *skb;
88 int err;
90 MPLS_ENTER;
92 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
93 if (skb == NULL) {
94 MPLS_DEBUG("Exit: EINVAL\n");
95 return;
98 err = mpls_fill_ilm(skb, ilm, 0, 0, 0, event);
99 if (err < 0) {
100 nlmsg_free(skb);
101 MPLS_DEBUG("Exit: EINVAL\n");
102 return;
104 genlmsg_multicast(skb, 0, MPLS_GRP_ILM, GFP_KERNEL);
105 MPLS_EXIT;
108 static int genl_mpls_ilm_new(struct sk_buff *skb, struct genl_info *info)
110 struct mpls_in_label_req *mil;
111 struct mpls_instr_req *instr = NULL;
112 int retval = -EINVAL;
114 MPLS_ENTER;
116 if (!info->attrs[MPLS_ATTR_ILM])
117 return -EINVAL;
119 if (info->attrs[MPLS_ATTR_INSTR]) {
120 instr = nla_data(info->attrs[MPLS_ATTR_INSTR]);
123 mil = nla_data(info->attrs[MPLS_ATTR_ILM]);
125 if (info->nlhdr->nlmsg_flags&NLM_F_CREATE)
126 retval = mpls_add_in_label(mil);
127 else
128 retval = 0;
130 if ((!retval) && instr &&
131 mil->mil_change_flag & MPLS_CHANGE_INSTR) {
132 memcpy(&instr->mir_label, &mil->mil_label,
133 sizeof(struct mpls_label));
134 retval = mpls_set_in_label_instrs(instr);
136 /* JLEU: should revert to old instr on failure */
137 if (retval)
138 mpls_del_in_label(mil);
141 if ((!retval) && mil->mil_change_flag & MPLS_CHANGE_PROTO)
142 retval = mpls_set_in_label_proto(mil);
144 MPLS_DEBUG("Exit: %d\n", retval);
145 return retval;
148 static int genl_mpls_ilm_del(struct sk_buff *skb, struct genl_info *info)
150 struct mpls_in_label_req *mil;
151 int retval = -EINVAL;
153 MPLS_ENTER;
155 mil = nla_data(info->attrs[MPLS_ATTR_ILM]);
156 retval = mpls_del_in_label(mil);
157 MPLS_DEBUG("Exit: %d\n", retval);
158 return retval;
161 static int genl_mpls_ilm_get(struct sk_buff *skb, struct genl_info *info)
163 struct mpls_in_label_req *mil;
164 struct mpls_ilm *ilm;
165 int retval = -EINVAL;
167 MPLS_ENTER;
168 if (!info->attrs[MPLS_ATTR_ILM])
169 goto err;
171 mil = nla_data(info->attrs[MPLS_ATTR_ILM]);
173 if (mil->mil_label.ml_type == MPLS_LABEL_KEY)
174 goto err;
176 ilm = mpls_get_ilm(mpls_label2key(mil->mil_label.ml_index,
177 &mil->mil_label));
178 if (!ilm) {
179 retval = -ESRCH;
180 } else {
181 if (mpls_fill_ilm(skb, ilm, info->snd_pid, info->snd_seq,
182 0, MPLS_CMD_NEWILM) < 0)
183 retval = -EINVAL;
185 mpls_ilm_release (ilm);
187 retval = genlmsg_unicast(&init_net, skb, info->snd_pid);
188 err:
189 MPLS_DEBUG("Exit: %d\n", retval);
190 return retval;
193 static int genl_mpls_ilm_dump(struct sk_buff *skb, struct netlink_callback *cb)
195 struct mpls_ilm *ilm;
196 int entries_to_skip;
197 int entry_count;
199 entries_to_skip = cb->args[0];
200 entry_count = 0;
202 MPLS_DEBUG("Enter: entry %d\n", entries_to_skip);
203 rcu_read_lock();
204 list_for_each_entry_rcu(ilm, &mpls_ilm_list, global) {
205 MPLS_DEBUG("Dump: entry %d\n", entry_count);
206 if (entry_count >= entries_to_skip) {
207 if (mpls_fill_ilm(skb, ilm, NETLINK_CB(cb->skb).pid,
208 cb->nlh->nlmsg_seq, NLM_F_MULTI,
209 MPLS_CMD_NEWILM) < 0) {
210 break;
213 entry_count++;
215 rcu_read_unlock();
216 cb->args[0] = entry_count;
218 MPLS_DEBUG("Exit: entry %d\n", entry_count);
219 return skb->len;
222 /* NHLFE netlink support */
224 static int mpls_fill_nhlfe(struct sk_buff *skb, struct mpls_nhlfe *nhlfe,
225 u32 pid, u32 seq, int flag, int event)
227 struct mpls_out_label_req mol;
228 struct gnet_stats_basic stats;
229 struct mpls_instr_req *instr;
230 void *hdr;
232 MPLS_ENTER;
234 hdr = genlmsg_put(skb, pid, seq, &genl_mpls, flag, event);
236 instr = kmalloc(sizeof(*instr), GFP_KERNEL);
237 if (unlikely(!instr))
238 goto nla_put_failure;
240 mol.mol_label.ml_type = MPLS_LABEL_KEY;
241 mol.mol_label.u.ml_key = nhlfe->nhlfe_key;
242 mol.mol_mtu = nhlfe->nhlfe_mtu;
243 mol.mol_propagate_ttl = nhlfe->nhlfe_propagate_ttl;
244 mpls_instrs_unbuild(nhlfe->nhlfe_instr, instr);
245 instr->mir_direction = MPLS_OUT;
246 memcpy(&stats, &nhlfe->nhlfe_stats, sizeof(stats));
247 /* need to get drops added here some how */
249 NLA_PUT(skb, MPLS_ATTR_NHLFE, sizeof(mol), &mol);
250 NLA_PUT(skb, MPLS_ATTR_INSTR, sizeof(*instr), instr);
251 NLA_PUT(skb, MPLS_ATTR_STATS, sizeof(stats), &stats);
253 kfree(instr);
255 MPLS_EXIT;
256 return genlmsg_end(skb, hdr);
258 nla_put_failure:
259 if (instr)
260 kfree(instr);
262 genlmsg_cancel(skb, hdr);
263 MPLS_DEBUG("Exit: -1\n");
264 return -ENOMEM;
267 void mpls_nhlfe_event(int event, struct mpls_nhlfe *nhlfe, int seq, int pid)
269 struct sk_buff *skb;
270 int err;
272 MPLS_ENTER;
273 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
274 if (skb == NULL) {
275 MPLS_DEBUG("Exit: EINVAL\n");
276 return;
279 err = mpls_fill_nhlfe(skb, nhlfe, pid, seq, 0, event);
280 if (err < 0) {
281 nlmsg_free(skb);
282 MPLS_DEBUG("Exit: EINVAL\n");
283 return;
285 genlmsg_multicast(skb, 0, MPLS_GRP_NHLFE, GFP_KERNEL);
286 MPLS_EXIT;
289 static int genl_mpls_nhlfe_new(struct sk_buff *skb, struct genl_info *info)
291 struct mpls_out_label_req *mol;
292 struct mpls_instr_req *instr = NULL;
293 int retval = -EINVAL;
295 MPLS_ENTER;
297 if (!info->attrs[MPLS_ATTR_NHLFE])
298 return -EINVAL;
300 if (info->attrs[MPLS_ATTR_INSTR]) {
301 instr = nla_data(info->attrs[MPLS_ATTR_INSTR]);
304 mol = nla_data(info->attrs[MPLS_ATTR_NHLFE]);
306 if (info->nlhdr->nlmsg_flags&NLM_F_CREATE) {
307 if (mol->mol_label.ml_type != MPLS_LABEL_KEY ||
308 mol->mol_label.u.ml_key)
309 retval = -EINVAL;
310 else {
311 retval = mpls_add_out_label(mol, info->snd_seq,
312 info->snd_pid);
314 } else {
315 retval = 0;
318 if ((!retval) && instr &&
319 mol->mol_change_flag & MPLS_CHANGE_INSTR) {
320 memcpy(&instr->mir_label, &mol->mol_label,
321 sizeof(struct mpls_label));
322 retval = mpls_set_out_label_instrs(instr);
323 /* JLEU: should revert to old instr on failure */
326 if ((!retval) && mol->mol_change_flag & MPLS_CHANGE_MTU)
327 retval = mpls_set_out_label_mtu(mol);
329 if ((!retval) && mol->mol_change_flag & MPLS_CHANGE_PROP_TTL)
330 retval = mpls_set_out_label_propagate_ttl(mol);
332 MPLS_DEBUG("Exit: %d\n", retval);
333 return retval;
336 static int genl_mpls_nhlfe_del(struct sk_buff *skb, struct genl_info *info)
338 struct mpls_out_label_req *mol;
339 int retval = -EINVAL;
341 MPLS_ENTER;
343 mol = nla_data(info->attrs[MPLS_ATTR_NHLFE]);
344 retval = mpls_del_out_label(mol);
345 MPLS_DEBUG("Exit: %d\n", retval);
346 return retval;
349 static int genl_mpls_nhlfe_get(struct sk_buff *skb, struct genl_info *info)
351 struct mpls_out_label_req *mol;
352 struct mpls_nhlfe *nhlfe;
353 int retval = -EINVAL;
355 MPLS_ENTER;
356 if (!info->attrs[MPLS_ATTR_NHLFE])
357 goto err;
359 mol = nla_data(info->attrs[MPLS_ATTR_NHLFE]);
361 if (mol->mol_label.ml_type != MPLS_LABEL_KEY)
362 goto err;
364 nhlfe = mpls_get_nhlfe(mol->mol_label.u.ml_key);
365 if (!nhlfe) {
366 retval = -ESRCH;
367 } else {
368 if (mpls_fill_nhlfe(skb, nhlfe, info->snd_pid, info->snd_seq,
369 0, MPLS_CMD_NEWNHLFE) < 0)
370 retval = -EINVAL;
372 mpls_nhlfe_release (nhlfe);
374 retval = genlmsg_unicast(&init_net, skb, info->snd_pid);
375 err:
376 MPLS_DEBUG("Exit: %d\n", retval);
377 return retval;
380 static int genl_mpls_nhlfe_dump(struct sk_buff *skb,
381 struct netlink_callback *cb)
383 struct mpls_nhlfe *nhlfe;
384 int entries_to_skip;
385 int entry_count;
387 entries_to_skip = cb->args[0];
388 entry_count = 0;
390 MPLS_DEBUG("Enter: entry %d\n", entries_to_skip);
391 rcu_read_lock();
392 list_for_each_entry_rcu(nhlfe, &mpls_nhlfe_list, global) {
393 MPLS_DEBUG("Dump: entry %d\n", entry_count);
394 if (entry_count >= entries_to_skip) {
395 if (mpls_fill_nhlfe(skb, nhlfe, NETLINK_CB(cb->skb).pid,
396 cb->nlh->nlmsg_seq, NLM_F_MULTI,
397 MPLS_CMD_NEWNHLFE) <= 0) {
398 break;
401 entry_count++;
403 rcu_read_unlock();
404 cb->args[0] = entry_count;
406 MPLS_DEBUG("Exit: entry %d\n", entry_count);
407 return skb->len;
410 /* XC netlink support */
412 static int mpls_fill_xc(struct sk_buff *skb, struct mpls_ilm *ilm,
413 struct mpls_nhlfe *nhlfe, u32 pid, u32 seq, int flag, int event)
415 struct mpls_xconnect_req xc;
416 void *hdr;
418 hdr = genlmsg_put(skb, pid, seq, &genl_mpls, flag, event);
420 memcpy(&xc.mx_in, &ilm->ilm_label, sizeof (struct mpls_label));
421 xc.mx_out.ml_type = MPLS_LABEL_KEY;
422 xc.mx_out.u.ml_key = nhlfe->nhlfe_key;
424 NLA_PUT(skb, MPLS_ATTR_XC, sizeof(xc), &xc);
426 MPLS_DEBUG("Exit: length\n");
427 return genlmsg_end(skb, hdr);
429 nla_put_failure:
430 genlmsg_cancel(skb, hdr);
431 MPLS_DEBUG("Exit: -1\n");
432 return -ENOMEM;
435 void mpls_xc_event(int event, struct mpls_ilm *ilm,
436 struct mpls_nhlfe *nhlfe)
438 struct sk_buff *skb;
439 int err;
441 MPLS_ENTER;
442 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
443 if (skb == NULL) {
444 MPLS_DEBUG("Exit: EINVAL\n");
445 return;
448 err = mpls_fill_xc(skb, ilm, nhlfe, 0, 0, 0, event);
449 if (err < 0) {
450 nlmsg_free(skb);
451 MPLS_DEBUG("Exit: EINVAL\n");
452 return;
454 genlmsg_multicast(skb, 0, MPLS_GRP_XC, GFP_KERNEL);
455 MPLS_EXIT;
458 static int genl_mpls_xc_new(struct sk_buff *skb, struct genl_info *info)
460 struct mpls_xconnect_req *xc;
461 int retval = -EINVAL;
463 MPLS_ENTER;
465 if (!info->attrs[MPLS_ATTR_XC])
466 return -EINVAL;
468 xc = nla_data(info->attrs[MPLS_ATTR_XC]);
470 if (!(info->nlhdr->nlmsg_flags&NLM_F_CREATE))
471 retval = -EINVAL;
472 else
473 retval = mpls_attach_in2out(xc);
474 MPLS_DEBUG("Exit: %d\n", retval);
475 return retval;
478 static int genl_mpls_xc_del(struct sk_buff *skb, struct genl_info *info)
480 struct mpls_xconnect_req *xc;
481 int retval = -EINVAL;
483 MPLS_ENTER;
485 xc = nla_data(info->attrs[MPLS_ATTR_XC]);
486 retval = mpls_detach_in2out(xc);
487 MPLS_DEBUG("Exit: %d\n", retval);
488 return retval;
491 static int genl_mpls_xc_get(struct sk_buff *skb, struct genl_info *info)
493 struct mpls_xconnect_req *xc;
494 struct mpls_ilm *ilm;
495 struct mpls_nhlfe *nhlfe;
496 struct mpls_instr *mi;
497 int retval = -EINVAL;
499 MPLS_ENTER;
500 if (!info->attrs[MPLS_ATTR_XC])
501 goto err;
503 xc = nla_data(info->attrs[MPLS_ATTR_XC]);
505 if (xc->mx_in.ml_type == MPLS_LABEL_KEY) {
506 retval = -EINVAL;
507 goto err;
510 ilm = mpls_get_ilm(mpls_label2key(xc->mx_in.ml_index,
511 &xc->mx_in));
512 if (!ilm) {
513 retval = -ESRCH;
514 } else {
515 /* Fetch the last instr, make sure it is FWD */
516 for (mi = ilm->ilm_instr;
517 mi->mi_next;mi = mi->mi_next); /* noop */
519 if (!mi || mi->mi_opcode != MPLS_OP_FWD) {
520 retval = -ENXIO;
521 } else {
522 nhlfe = mi->mi_data;
524 if (mpls_fill_xc(skb, ilm, nhlfe, info->snd_pid,
525 info->snd_seq, 0, MPLS_CMD_NEWXC) < 0)
526 retval = -EINVAL;
528 mpls_ilm_release (ilm);
530 retval = genlmsg_unicast(&init_net, skb, info->snd_pid);
531 err:
532 MPLS_DEBUG("Exit: %d\n", retval);
533 return retval;
536 static int genl_mpls_xc_dump(struct sk_buff *skb, struct netlink_callback *cb)
538 struct mpls_ilm *ilm;
539 struct mpls_nhlfe *nhlfe;
540 struct mpls_instr *mi;
541 int entries_to_skip;
542 int entry_count;
544 entries_to_skip = cb->args[0];
545 entry_count = 0;
547 MPLS_DEBUG("Enter: entry %d\n", entries_to_skip);
548 rcu_read_lock();
549 list_for_each_entry_rcu(ilm, &mpls_ilm_list, global) {
550 MPLS_DEBUG("Dump: entry %d\n", entry_count);
551 if (entry_count >= entries_to_skip) {
552 /* Fetch the last instr, make sure it is FWD */
553 for (mi = ilm->ilm_instr;
554 mi->mi_next;mi = mi->mi_next); /* noop */
556 if (!mi || mi->mi_opcode != MPLS_OP_FWD)
557 continue;
559 nhlfe = mi->mi_data;
561 if (mpls_fill_xc(skb, ilm, nhlfe,
562 NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
563 NLM_F_MULTI, MPLS_CMD_NEWXC) < 0) {
564 break;
567 entry_count++;
569 rcu_read_unlock();
570 cb->args[0] = entry_count;
572 MPLS_DEBUG("Exit: entry %d\n", entry_count);
573 return skb->len;
576 /* LABELSPACE netlink support */
578 static int mpls_fill_labelspace(struct sk_buff *skb, struct net_device *dev,
579 u32 pid, u32 seq, int flag, int event)
581 struct mpls_labelspace_req ls;
582 void *hdr;
584 hdr = genlmsg_put(skb, pid, seq, &genl_mpls, flag, event);
586 ls.mls_ifindex = dev->ifindex;
587 ls.mls_labelspace = mpls_get_labelspace_by_index(dev->ifindex);
589 NLA_PUT(skb, MPLS_ATTR_LABELSPACE, sizeof(ls), &ls);
591 MPLS_DEBUG("Exit: length\n");
592 return genlmsg_end(skb, hdr);
594 nla_put_failure:
595 genlmsg_cancel(skb, hdr);
596 MPLS_DEBUG("Exit: -1\n");
597 return -ENOMEM;
600 void mpls_labelspace_event(int event, struct net_device *dev)
602 struct sk_buff *skb;
603 int err;
605 MPLS_ENTER;
606 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
607 if (skb == NULL) {
608 MPLS_DEBUG("Exit: EINVAL\n");
609 return;
612 err = mpls_fill_labelspace(skb, dev, 0, 0, 0, event);
613 if (err < 0) {
614 nlmsg_free(skb);
615 MPLS_DEBUG("Exit: EINVAL\n");
616 return;
618 genlmsg_multicast(skb, 0, MPLS_GRP_LABELSPACE, GFP_KERNEL);
619 MPLS_EXIT;
622 static int genl_mpls_labelspace_set(struct sk_buff *skb, struct genl_info *info)
624 struct mpls_labelspace_req *ls;
625 int retval = -EINVAL;
627 MPLS_ENTER;
628 ls = nla_data(info->attrs[MPLS_ATTR_LABELSPACE]);
629 retval = mpls_set_labelspace(ls);
630 MPLS_DEBUG("Exit: %d\n", retval);
631 return retval;
634 static int genl_mpls_labelspace_get(struct sk_buff *skb, struct genl_info *info)
636 struct mpls_labelspace_req *ls;
637 struct net_device *dev;
638 int retval = -EINVAL;
640 MPLS_ENTER;
641 if (!info->attrs[MPLS_ATTR_LABELSPACE])
642 goto err;
644 ls = nla_data(info->attrs[MPLS_ATTR_LABELSPACE]);
645 dev = dev_get_by_index(&init_net, ls->mls_ifindex);
646 if (!dev) {
647 retval = -ESRCH;
648 } else {
649 if (mpls_fill_labelspace(skb, dev, info->snd_pid,
650 info->snd_seq, 0, MPLS_CMD_SETLABELSPACE) < 0)
651 retval = -EINVAL;
652 dev_put (dev);
654 retval = genlmsg_unicast(&init_net, skb, info->snd_pid);
655 err:
656 MPLS_DEBUG("Exit: %d\n", retval);
657 return retval;
660 static int genl_mpls_labelspace_dump(struct sk_buff *skb,
661 struct netlink_callback *cb)
663 struct net_device *dev;
664 int entries_to_skip;
665 int entry_count;
667 entries_to_skip = cb->args[0];
668 entry_count = 0;
670 MPLS_DEBUG("Enter: entry %d\n", entries_to_skip);
671 read_lock(&dev_base_lock);
672 for_each_netdev(&init_net, dev) {
673 MPLS_DEBUG("Dump: entry %d\n", entry_count);
674 if (entry_count >= entries_to_skip) {
675 if (mpls_fill_labelspace(skb, dev,
676 NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
677 NLM_F_MULTI, MPLS_CMD_SETLABELSPACE) < 0) {
678 break;
681 entry_count++;
683 read_unlock(&dev_base_lock);
684 cb->args[0] = entry_count;
686 MPLS_DEBUG("Exit: entry %d\n", entry_count);
687 return skb->len;
690 static struct nla_policy genl_mpls_policy[MPLS_ATTR_MAX+1] __read_mostly = {
691 [MPLS_ATTR_ILM] = { .len = sizeof(struct mpls_in_label_req) },
692 [MPLS_ATTR_NHLFE] = { .len = sizeof(struct mpls_out_label_req) },
693 [MPLS_ATTR_XC] = { .len = sizeof(struct mpls_xconnect_req) },
694 [MPLS_ATTR_LABELSPACE] = {.len = sizeof(struct mpls_labelspace_req)},
695 [MPLS_ATTR_INSTR] = { .len = sizeof(struct mpls_instr_req) },
696 [MPLS_ATTR_STATS] = { .len = sizeof(struct gnet_stats_basic) },
699 static struct genl_ops genl_mpls_ilm_new_ops = {
700 .cmd = MPLS_CMD_NEWILM,
701 .doit = genl_mpls_ilm_new,
702 .policy = genl_mpls_policy,
704 static struct genl_ops genl_mpls_ilm_del_ops = {
705 .cmd = MPLS_CMD_DELILM,
706 .doit = genl_mpls_ilm_del,
707 .policy = genl_mpls_policy,
709 static struct genl_ops genl_mpls_ilm_get_ops = {
710 .cmd = MPLS_CMD_GETILM,
711 .doit = genl_mpls_ilm_get,
712 .dumpit = genl_mpls_ilm_dump,
713 .policy = genl_mpls_policy,
716 static struct genl_ops genl_mpls_nhlfe_new_ops = {
717 .cmd = MPLS_CMD_NEWNHLFE,
718 .doit = genl_mpls_nhlfe_new,
719 .policy = genl_mpls_policy,
721 static struct genl_ops genl_mpls_nhlfe_del_ops = {
722 .cmd = MPLS_CMD_DELNHLFE,
723 .doit = genl_mpls_nhlfe_del,
724 .policy = genl_mpls_policy,
726 static struct genl_ops genl_mpls_nhlfe_get_ops = {
727 .cmd = MPLS_CMD_GETNHLFE,
728 .doit = genl_mpls_nhlfe_get,
729 .dumpit = genl_mpls_nhlfe_dump,
730 .policy = genl_mpls_policy,
733 static struct genl_ops genl_mpls_xc_new_ops = {
734 .cmd = MPLS_CMD_NEWXC,
735 .doit = genl_mpls_xc_new,
736 .policy = genl_mpls_policy,
738 static struct genl_ops genl_mpls_xc_del_ops = {
739 .cmd = MPLS_CMD_DELXC,
740 .doit = genl_mpls_xc_del,
741 .policy = genl_mpls_policy,
743 static struct genl_ops genl_mpls_xc_get_ops = {
744 .cmd = MPLS_CMD_GETXC,
745 .doit = genl_mpls_xc_get,
746 .dumpit = genl_mpls_xc_dump,
747 .policy = genl_mpls_policy,
750 static struct genl_ops genl_mpls_labelspace_set_ops = {
751 .cmd = MPLS_CMD_SETLABELSPACE,
752 .doit = genl_mpls_labelspace_set,
753 .policy = genl_mpls_policy,
755 static struct genl_ops genl_mpls_labelspace_get_ops = {
756 .cmd = MPLS_CMD_GETLABELSPACE,
757 .doit = genl_mpls_labelspace_get,
758 .dumpit = genl_mpls_labelspace_dump,
759 .policy = genl_mpls_policy,
762 int __init mpls_netlink_init(void)
764 int err;
766 err = genl_register_family(&genl_mpls);
768 err += genl_register_ops(&genl_mpls, &genl_mpls_ilm_new_ops);
769 err += genl_register_ops(&genl_mpls, &genl_mpls_ilm_del_ops);
770 err += genl_register_ops(&genl_mpls, &genl_mpls_ilm_get_ops);
772 err += genl_register_ops(&genl_mpls, &genl_mpls_nhlfe_new_ops);
773 err += genl_register_ops(&genl_mpls, &genl_mpls_nhlfe_del_ops);
774 err += genl_register_ops(&genl_mpls, &genl_mpls_nhlfe_get_ops);
776 err += genl_register_ops(&genl_mpls, &genl_mpls_xc_new_ops);
777 err += genl_register_ops(&genl_mpls, &genl_mpls_xc_del_ops);
778 err += genl_register_ops(&genl_mpls, &genl_mpls_xc_get_ops);
780 err += genl_register_ops(&genl_mpls, &genl_mpls_labelspace_set_ops);
781 err += genl_register_ops(&genl_mpls, &genl_mpls_labelspace_get_ops);
783 if (err) {
784 printk(MPLS_ERR "MPLS: failed to register with genetlink\n");
785 return -EINVAL;
788 return 0;
791 void __exit mpls_netlink_exit(void)
793 genl_unregister_ops(&genl_mpls, &genl_mpls_labelspace_get_ops);
794 genl_unregister_ops(&genl_mpls, &genl_mpls_labelspace_set_ops);
796 genl_unregister_ops(&genl_mpls, &genl_mpls_xc_del_ops);
797 genl_unregister_ops(&genl_mpls, &genl_mpls_xc_new_ops);
798 genl_unregister_ops(&genl_mpls, &genl_mpls_xc_get_ops);
800 genl_unregister_ops(&genl_mpls, &genl_mpls_nhlfe_del_ops);
801 genl_unregister_ops(&genl_mpls, &genl_mpls_nhlfe_new_ops);
802 genl_unregister_ops(&genl_mpls, &genl_mpls_nhlfe_get_ops);
804 genl_unregister_ops(&genl_mpls, &genl_mpls_ilm_del_ops);
805 genl_unregister_ops(&genl_mpls, &genl_mpls_ilm_new_ops);
806 genl_unregister_ops(&genl_mpls, &genl_mpls_ilm_get_ops);
808 genl_unregister_family(&genl_mpls);