1 /*****************************************************************************
3 * An implementation of the MPLS (MultiProtocol Label
4 * Switching) Architecture for Linux.
6 * NetLink Interface for MPLS subsystem
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>
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
= {
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
;
55 hdr
= genlmsg_put(skb
, pid
, seq
, &genl_mpls
, flag
, event
);
57 instr
= kmalloc(sizeof(*instr
), GFP_KERNEL
);
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
);
75 return genlmsg_end(skb
, hdr
);
80 genlmsg_cancel(skb
, hdr
);
81 MPLS_DEBUG("Exit: -1\n");
85 void mpls_ilm_event(int event
, struct mpls_ilm
*ilm
)
92 skb
= nlmsg_new(NLMSG_GOODSIZE
, GFP_ATOMIC
);
94 MPLS_DEBUG("Exit: EINVAL\n");
98 err
= mpls_fill_ilm(skb
, ilm
, 0, 0, 0, event
);
101 MPLS_DEBUG("Exit: EINVAL\n");
104 genlmsg_multicast(skb
, 0, MPLS_GRP_ILM
, GFP_KERNEL
);
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
;
116 if (!info
->attrs
[MPLS_ATTR_ILM
])
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
);
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 */
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
);
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
;
155 mil
= nla_data(info
->attrs
[MPLS_ATTR_ILM
]);
156 retval
= mpls_del_in_label(mil
);
157 MPLS_DEBUG("Exit: %d\n", 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
;
168 if (!info
->attrs
[MPLS_ATTR_ILM
])
171 mil
= nla_data(info
->attrs
[MPLS_ATTR_ILM
]);
173 if (mil
->mil_label
.ml_type
== MPLS_LABEL_KEY
)
176 ilm
= mpls_get_ilm(mpls_label2key(mil
->mil_label
.ml_index
,
181 if (mpls_fill_ilm(skb
, ilm
, info
->snd_pid
, info
->snd_seq
,
182 0, MPLS_CMD_NEWILM
) < 0)
185 mpls_ilm_release (ilm
);
187 retval
= genlmsg_unicast(&init_net
, skb
, info
->snd_pid
);
189 MPLS_DEBUG("Exit: %d\n", retval
);
193 static int genl_mpls_ilm_dump(struct sk_buff
*skb
, struct netlink_callback
*cb
)
195 struct mpls_ilm
*ilm
;
199 entries_to_skip
= cb
->args
[0];
202 MPLS_DEBUG("Enter: entry %d\n", entries_to_skip
);
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) {
216 cb
->args
[0] = entry_count
;
218 MPLS_DEBUG("Exit: entry %d\n", entry_count
);
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
;
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
);
256 return genlmsg_end(skb
, hdr
);
262 genlmsg_cancel(skb
, hdr
);
263 MPLS_DEBUG("Exit: -1\n");
267 void mpls_nhlfe_event(int event
, struct mpls_nhlfe
*nhlfe
, int seq
, int pid
)
273 skb
= nlmsg_new(NLMSG_GOODSIZE
, GFP_ATOMIC
);
275 MPLS_DEBUG("Exit: EINVAL\n");
279 err
= mpls_fill_nhlfe(skb
, nhlfe
, pid
, seq
, 0, event
);
282 MPLS_DEBUG("Exit: EINVAL\n");
285 genlmsg_multicast(skb
, 0, MPLS_GRP_NHLFE
, GFP_KERNEL
);
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
;
297 if (!info
->attrs
[MPLS_ATTR_NHLFE
])
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
)
311 retval
= mpls_add_out_label(mol
, info
->snd_seq
,
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
);
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
;
343 mol
= nla_data(info
->attrs
[MPLS_ATTR_NHLFE
]);
344 retval
= mpls_del_out_label(mol
);
345 MPLS_DEBUG("Exit: %d\n", 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
;
356 if (!info
->attrs
[MPLS_ATTR_NHLFE
])
359 mol
= nla_data(info
->attrs
[MPLS_ATTR_NHLFE
]);
361 if (mol
->mol_label
.ml_type
!= MPLS_LABEL_KEY
)
364 nhlfe
= mpls_get_nhlfe(mol
->mol_label
.u
.ml_key
);
368 if (mpls_fill_nhlfe(skb
, nhlfe
, info
->snd_pid
, info
->snd_seq
,
369 0, MPLS_CMD_NEWNHLFE
) < 0)
372 mpls_nhlfe_release (nhlfe
);
374 retval
= genlmsg_unicast(&init_net
, skb
, info
->snd_pid
);
376 MPLS_DEBUG("Exit: %d\n", retval
);
380 static int genl_mpls_nhlfe_dump(struct sk_buff
*skb
,
381 struct netlink_callback
*cb
)
383 struct mpls_nhlfe
*nhlfe
;
387 entries_to_skip
= cb
->args
[0];
390 MPLS_DEBUG("Enter: entry %d\n", entries_to_skip
);
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) {
404 cb
->args
[0] = entry_count
;
406 MPLS_DEBUG("Exit: entry %d\n", entry_count
);
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
;
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
);
430 genlmsg_cancel(skb
, hdr
);
431 MPLS_DEBUG("Exit: -1\n");
435 void mpls_xc_event(int event
, struct mpls_ilm
*ilm
,
436 struct mpls_nhlfe
*nhlfe
)
442 skb
= nlmsg_new(NLMSG_GOODSIZE
, GFP_ATOMIC
);
444 MPLS_DEBUG("Exit: EINVAL\n");
448 err
= mpls_fill_xc(skb
, ilm
, nhlfe
, 0, 0, 0, event
);
451 MPLS_DEBUG("Exit: EINVAL\n");
454 genlmsg_multicast(skb
, 0, MPLS_GRP_XC
, GFP_KERNEL
);
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
;
465 if (!info
->attrs
[MPLS_ATTR_XC
])
468 xc
= nla_data(info
->attrs
[MPLS_ATTR_XC
]);
470 if (!(info
->nlhdr
->nlmsg_flags
&NLM_F_CREATE
))
473 retval
= mpls_attach_in2out(xc
);
474 MPLS_DEBUG("Exit: %d\n", 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
;
485 xc
= nla_data(info
->attrs
[MPLS_ATTR_XC
]);
486 retval
= mpls_detach_in2out(xc
);
487 MPLS_DEBUG("Exit: %d\n", 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
;
500 if (!info
->attrs
[MPLS_ATTR_XC
])
503 xc
= nla_data(info
->attrs
[MPLS_ATTR_XC
]);
505 if (xc
->mx_in
.ml_type
== MPLS_LABEL_KEY
) {
510 ilm
= mpls_get_ilm(mpls_label2key(xc
->mx_in
.ml_index
,
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
) {
524 if (mpls_fill_xc(skb
, ilm
, nhlfe
, info
->snd_pid
,
525 info
->snd_seq
, 0, MPLS_CMD_NEWXC
) < 0)
528 mpls_ilm_release (ilm
);
530 retval
= genlmsg_unicast(&init_net
, skb
, info
->snd_pid
);
532 MPLS_DEBUG("Exit: %d\n", 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
;
544 entries_to_skip
= cb
->args
[0];
547 MPLS_DEBUG("Enter: entry %d\n", entries_to_skip
);
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
)
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) {
570 cb
->args
[0] = entry_count
;
572 MPLS_DEBUG("Exit: entry %d\n", entry_count
);
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
;
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
);
595 genlmsg_cancel(skb
, hdr
);
596 MPLS_DEBUG("Exit: -1\n");
600 void mpls_labelspace_event(int event
, struct net_device
*dev
)
606 skb
= nlmsg_new(NLMSG_GOODSIZE
, GFP_ATOMIC
);
608 MPLS_DEBUG("Exit: EINVAL\n");
612 err
= mpls_fill_labelspace(skb
, dev
, 0, 0, 0, event
);
615 MPLS_DEBUG("Exit: EINVAL\n");
618 genlmsg_multicast(skb
, 0, MPLS_GRP_LABELSPACE
, GFP_KERNEL
);
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
;
628 ls
= nla_data(info
->attrs
[MPLS_ATTR_LABELSPACE
]);
629 retval
= mpls_set_labelspace(ls
);
630 MPLS_DEBUG("Exit: %d\n", 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
;
641 if (!info
->attrs
[MPLS_ATTR_LABELSPACE
])
644 ls
= nla_data(info
->attrs
[MPLS_ATTR_LABELSPACE
]);
645 dev
= dev_get_by_index(&init_net
, ls
->mls_ifindex
);
649 if (mpls_fill_labelspace(skb
, dev
, info
->snd_pid
,
650 info
->snd_seq
, 0, MPLS_CMD_SETLABELSPACE
) < 0)
654 retval
= genlmsg_unicast(&init_net
, skb
, info
->snd_pid
);
656 MPLS_DEBUG("Exit: %d\n", retval
);
660 static int genl_mpls_labelspace_dump(struct sk_buff
*skb
,
661 struct netlink_callback
*cb
)
663 struct net_device
*dev
;
667 entries_to_skip
= cb
->args
[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) {
683 read_unlock(&dev_base_lock
);
684 cb
->args
[0] = entry_count
;
686 MPLS_DEBUG("Exit: entry %d\n", entry_count
);
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)
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
);
784 printk(MPLS_ERR
"MPLS: failed to register with genetlink\n");
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
);