summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.indent.pro1
-rw-r--r--.travis.yml8
-rwxr-xr-x.travis/run.sh17
-rw-r--r--Android.bp71
l---------LICENSE1
-rw-r--r--METADATA19
-rw-r--r--Makefile.am1023
-rw-r--r--NOTICE506
-rw-r--r--README.version3
-rw-r--r--configure.ac59
-rw-r--r--doc/Doxyfile.in2
-rw-r--r--doc/Makefile.am23
-rw-r--r--doc/api/.gitignore1
-rw-r--r--doc/configure.ac11
-rw-r--r--doc/m4/ax_python.m497
-rw-r--r--doc/route.txt112
-rw-r--r--doc/src/toc.c6
-rw-r--r--etc/pktloc2
-rw-r--r--include/Makefile.am153
-rw-r--r--include/linux-private/linux/can/netlink.h30
-rw-r--r--include/linux-private/linux/fib_rules.h29
-rw-r--r--include/linux-private/linux/gen_stats.h13
-rw-r--r--include/linux-private/linux/genetlink.h10
-rw-r--r--include/linux-private/linux/if.h293
-rw-r--r--include/linux-private/linux/if_addr.h8
-rw-r--r--include/linux-private/linux/if_arp.h10
-rw-r--r--include/linux-private/linux/if_bad.h146
-rw-r--r--include/linux-private/linux/if_bridge.h122
-rw-r--r--include/linux-private/linux/if_ether.h52
-rw-r--r--include/linux-private/linux/if_link.h566
-rw-r--r--include/linux-private/linux/if_macsec.h177
-rw-r--r--include/linux-private/linux/if_tunnel.h57
-rw-r--r--include/linux-private/linux/if_vlan.h7
-rw-r--r--include/linux-private/linux/in.h301
-rw-r--r--include/linux-private/linux/in6.h298
-rw-r--r--include/linux-private/linux/inet_diag.h205
-rw-r--r--include/linux-private/linux/ip.h11
-rw-r--r--include/linux-private/linux/ip_mp_alg.h22
-rw-r--r--include/linux-private/linux/ipv6.h48
-rw-r--r--include/linux-private/linux/libc-compat.h267
-rw-r--r--include/linux-private/linux/lwtunnel.h71
-rw-r--r--include/linux-private/linux/mpls.h77
-rw-r--r--include/linux-private/linux/mpls_iptunnel.h31
-rw-r--r--include/linux-private/linux/neighbour.h19
-rw-r--r--include/linux-private/linux/netconf.h30
-rw-r--r--include/linux-private/linux/netfilter.h33
-rw-r--r--include/linux-private/linux/netfilter/nf_conntrack_common.h41
-rw-r--r--include/linux-private/linux/netfilter/nfnetlink.h43
-rw-r--r--include/linux-private/linux/netfilter/nfnetlink_compat.h3
-rw-r--r--include/linux-private/linux/netfilter/nfnetlink_conntrack.h43
-rw-r--r--include/linux-private/linux/netfilter/nfnetlink_log.h8
-rw-r--r--include/linux-private/linux/netfilter/nfnetlink_queue.h33
-rw-r--r--include/linux-private/linux/netlink.h130
-rw-r--r--include/linux-private/linux/pkt_cls.h299
-rw-r--r--include/linux-private/linux/pkt_sched.h529
-rw-r--r--include/linux-private/linux/rtnetlink.h164
-rw-r--r--include/linux-private/linux/snmp.h43
-rw-r--r--include/linux-private/linux/sock_diag.h39
-rw-r--r--include/linux-private/linux/socket.h22
-rw-r--r--include/linux-private/linux/tc_act/tc_gact.h34
-rw-r--r--include/linux-private/linux/tc_act/tc_mirred.h8
-rw-r--r--include/linux-private/linux/tc_act/tc_skbedit.h54
-rw-r--r--include/linux-private/linux/tc_act/tc_vlan.h39
-rw-r--r--include/linux-private/linux/tc_ematch/tc_em_meta.h6
-rw-r--r--include/linux-private/linux/veth.h13
-rw-r--r--include/linux-private/linux/xfrm.h540
-rw-r--r--include/linux/netfilter/nfnetlink_acct.h (renamed from include/linux-private/linux/netfilter/nfnetlink_acct.h)0
-rw-r--r--include/netlink-private/cache-api.h3
-rw-r--r--include/netlink-private/netlink.h45
-rw-r--r--include/netlink-private/object-api.h10
-rw-r--r--include/netlink-private/route/link/api.h46
-rw-r--r--include/netlink-private/route/link/sriov.h34
-rw-r--r--include/netlink-private/route/mpls.h15
-rw-r--r--include/netlink-private/route/nexthop-encap.h35
-rw-r--r--include/netlink-private/route/tc-api.h7
-rw-r--r--include/netlink-private/socket.h2
-rw-r--r--include/netlink-private/tc.h5
-rw-r--r--include/netlink-private/types.h354
-rw-r--r--include/netlink-private/utils.h223
-rw-r--r--include/netlink/addr.h41
-rw-r--r--include/netlink/attr.h94
-rw-r--r--include/netlink/cache.h13
-rw-r--r--include/netlink/cli/link.h4
-rw-r--r--include/netlink/cli/neigh.h3
-rw-r--r--include/netlink/cli/utils.h12
-rw-r--r--include/netlink/data.h17
-rw-r--r--include/netlink/errno.h3
-rw-r--r--include/netlink/fib_lookup/lookup.h7
-rw-r--r--include/netlink/genl/genl.h4
-rw-r--r--include/netlink/handlers.h5
-rw-r--r--include/netlink/hashtable.h3
-rw-r--r--include/netlink/idiag/idiagnl.h123
-rw-r--r--include/netlink/idiag/msg.h2
-rw-r--r--include/netlink/idiag/req.h4
-rw-r--r--include/netlink/list.h16
-rw-r--r--include/netlink/msg.h6
-rw-r--r--include/netlink/netfilter/exp.h3
-rw-r--r--include/netlink/netfilter/log.h2
-rw-r--r--include/netlink/netfilter/queue.h2
-rw-r--r--include/netlink/netfilter/queue_msg.h2
-rw-r--r--include/netlink/netlink-compat.h4
-rw-r--r--include/netlink/netlink.h8
-rw-r--r--include/netlink/object.h2
-rw-r--r--include/netlink/route/act/gact.h31
-rw-r--r--include/netlink/route/act/skbedit.h37
-rw-r--r--include/netlink/route/act/vlan.h38
-rw-r--r--include/netlink/route/action.h2
-rw-r--r--include/netlink/route/class.h3
-rw-r--r--include/netlink/route/classifier.h2
-rw-r--r--include/netlink/route/cls/basic.h1
-rw-r--r--include/netlink/route/cls/ematch.h2
-rw-r--r--include/netlink/route/cls/ematch/cmp.h2
-rw-r--r--include/netlink/route/cls/matchall.h36
-rw-r--r--include/netlink/route/cls/u32.h5
-rw-r--r--include/netlink/route/link.h25
-rw-r--r--include/netlink/route/link/bridge.h34
-rw-r--r--include/netlink/route/link/can.h4
-rw-r--r--include/netlink/route/link/geneve.h60
-rw-r--r--include/netlink/route/link/inet6.h53
-rw-r--r--include/netlink/route/link/ip6tnl.h4
-rw-r--r--include/netlink/route/link/ipgre.h5
-rw-r--r--include/netlink/route/link/ipip.h3
-rw-r--r--include/netlink/route/link/ipvlan.h37
-rw-r--r--include/netlink/route/link/ipvti.h10
-rw-r--r--include/netlink/route/link/macsec.h75
-rw-r--r--include/netlink/route/link/macvlan.h18
-rw-r--r--include/netlink/route/link/macvtap.h46
-rw-r--r--include/netlink/route/link/ppp.h30
-rw-r--r--include/netlink/route/link/sit.h20
-rw-r--r--include/netlink/route/link/sriov.h145
-rw-r--r--include/netlink/route/link/vrf.h32
-rw-r--r--include/netlink/route/link/vxlan.h48
-rw-r--r--include/netlink/route/link/xfrmi.h37
-rw-r--r--include/netlink/route/neighbour.h11
-rw-r--r--include/netlink/route/neightbl.h1
-rw-r--r--include/netlink/route/netconf.h44
-rw-r--r--include/netlink/route/nexthop.h12
-rw-r--r--include/netlink/route/qdisc/hfsc.h39
-rw-r--r--include/netlink/route/qdisc/htb.h16
-rw-r--r--include/netlink/route/qdisc/mqprio.h48
-rw-r--r--include/netlink/route/qdisc/netem.h1
-rw-r--r--include/netlink/route/qdisc/red.h3
-rw-r--r--include/netlink/route/route.h3
-rw-r--r--include/netlink/route/rule.h18
-rw-r--r--include/netlink/route/tc.h4
-rw-r--r--include/netlink/socket.h1
-rw-r--r--include/netlink/utils.h198
-rw-r--r--include/netlink/version.h12
-rw-r--r--include/netlink/xfrm/ae.h111
-rw-r--r--include/netlink/xfrm/lifetime.h87
-rw-r--r--include/netlink/xfrm/sa.h180
-rw-r--r--include/netlink/xfrm/selector.h100
-rw-r--r--include/netlink/xfrm/sp.h142
-rw-r--r--include/netlink/xfrm/template.h101
-rw-r--r--lib/Makefile.am135
-rw-r--r--lib/addr.c202
-rw-r--r--lib/attr.c234
-rw-r--r--lib/cache.c135
-rw-r--r--lib/cache_mngr.c139
-rw-r--r--lib/cache_mngt.c6
-rw-r--r--lib/cli/cls/basic.c4
-rw-r--r--lib/cli/cls/cgroup.c4
-rw-r--r--lib/cli/qdisc/bfifo.c4
-rw-r--r--lib/cli/qdisc/blackhole.c4
-rw-r--r--lib/cli/qdisc/fq_codel.c4
-rw-r--r--lib/cli/qdisc/hfsc.c252
-rw-r--r--lib/cli/qdisc/htb.c8
-rw-r--r--lib/cli/qdisc/pfifo.c4
-rw-r--r--lib/cli/qdisc/plug.c6
-rw-r--r--lib/data.c32
-rw-r--r--lib/error.c2
-rw-r--r--lib/fib_lookup/lookup.c10
-rw-r--r--lib/fib_lookup/request.c7
-rw-r--r--lib/genl/ctrl.c1
-rw-r--r--lib/genl/family.c31
-rw-r--r--lib/genl/genl.c14
-rw-r--r--lib/genl/mngt.c49
-rw-r--r--lib/handlers.c13
-rw-r--r--lib/hash.c47
-rw-r--r--lib/hashtable.c3
-rw-r--r--lib/idiag/idiag.c157
-rw-r--r--lib/idiag/idiag_meminfo_obj.c23
-rw-r--r--lib/idiag/idiag_msg_obj.c351
-rw-r--r--lib/idiag/idiag_req_obj.c3
-rw-r--r--lib/idiag/idiag_vegasinfo_obj.c24
-rw-r--r--lib/mpls.c109
-rw-r--r--lib/msg.c25
-rw-r--r--lib/netfilter/ct.c30
-rw-r--r--lib/netfilter/ct_obj.c103
-rw-r--r--lib/netfilter/exp.c21
-rw-r--r--lib/netfilter/exp_obj.c83
-rw-r--r--lib/netfilter/log.c1
-rw-r--r--lib/netfilter/log_msg.c15
-rw-r--r--lib/netfilter/log_msg_obj.c1
-rw-r--r--lib/netfilter/log_obj.c31
-rw-r--r--lib/netfilter/netfilter.c23
-rw-r--r--lib/netfilter/nfnl.c6
-rw-r--r--lib/netfilter/queue.c1
-rw-r--r--lib/netfilter/queue_msg.c15
-rw-r--r--lib/netfilter/queue_msg_obj.c40
-rw-r--r--lib/netfilter/queue_obj.c23
-rw-r--r--lib/nl.c172
-rw-r--r--lib/object.c46
-rw-r--r--lib/route/act.c27
-rw-r--r--lib/route/act/gact.c183
-rw-r--r--lib/route/act/mirred.c2
-rw-r--r--lib/route/act/skbedit.c290
-rw-r--r--lib/route/act/vlan.c426
-rw-r--r--lib/route/addr.c159
-rw-r--r--lib/route/class.c33
-rw-r--r--lib/route/classid.c10
-rw-r--r--lib/route/cls.c22
-rw-r--r--lib/route/cls/basic.c19
-rw-r--r--lib/route/cls/cgroup.c17
-rw-r--r--lib/route/cls/ematch.c60
-rw-r--r--lib/route/cls/ematch/cmp.c1
-rw-r--r--lib/route/cls/ematch/meta.c98
-rw-r--r--lib/route/cls/ematch/nbyte.c3
-rw-r--r--lib/route/cls/ematch/text.c6
-rw-r--r--lib/route/cls/ematch_grammar.l4
-rw-r--r--lib/route/cls/ematch_syntax.y10
-rw-r--r--lib/route/cls/mall.c305
-rw-r--r--lib/route/cls/police.c10
-rw-r--r--lib/route/cls/u32.c186
-rw-r--r--lib/route/link.c857
-rw-r--r--lib/route/link/api.c22
-rw-r--r--lib/route/link/bonding.c1
-rw-r--r--lib/route/link/bridge.c478
-rw-r--r--lib/route/link/can.c26
-rw-r--r--lib/route/link/geneve.c810
-rw-r--r--lib/route/link/ifb.c40
-rw-r--r--lib/route/link/inet.c61
-rw-r--r--lib/route/link/inet6.c317
-rw-r--r--lib/route/link/ip6tnl.c23
-rw-r--r--lib/route/link/ipgre.c149
-rw-r--r--lib/route/link/ipip.c23
-rw-r--r--lib/route/link/ipvlan.c277
-rw-r--r--lib/route/link/ipvti.c33
-rw-r--r--lib/route/link/macsec.c850
-rw-r--r--lib/route/link/macvlan.c603
-rw-r--r--lib/route/link/ppp.c224
-rw-r--r--lib/route/link/sit.c323
-rw-r--r--lib/route/link/sriov.c1466
-rw-r--r--lib/route/link/veth.c11
-rw-r--r--lib/route/link/vlan.c79
-rw-r--r--lib/route/link/vrf.c264
-rw-r--r--lib/route/link/vxlan.c859
-rw-r--r--lib/route/link/xfrmi.c319
-rw-r--r--lib/route/neigh.c260
-rw-r--r--lib/route/neightbl.c53
-rw-r--r--lib/route/netconf.c584
-rw-r--r--lib/route/nexthop.c138
-rw-r--r--lib/route/nexthop_encap.c104
-rw-r--r--lib/route/nh_encap_mpls.c135
-rw-r--r--lib/route/pktloc.c9
-rw-r--r--lib/route/pktloc_grammar.l4
-rw-r--r--lib/route/qdisc.c3
-rw-r--r--lib/route/qdisc/cbq.c10
-rw-r--r--lib/route/qdisc/hfsc.c351
-rw-r--r--lib/route/qdisc/htb.c219
-rw-r--r--lib/route/qdisc/mqprio.c605
-rw-r--r--lib/route/qdisc/netem.c301
-rw-r--r--lib/route/qdisc/prio.c12
-rw-r--r--lib/route/qdisc/tbf.c42
-rw-r--r--lib/route/route.c2
-rw-r--r--lib/route/route_obj.c294
-rw-r--r--lib/route/route_utils.c31
-rw-r--r--lib/route/rtnl.c41
-rw-r--r--lib/route/rule.c311
-rw-r--r--lib/route/tc.c206
-rw-r--r--lib/socket.c219
-rw-r--r--lib/utils.c429
-rw-r--r--lib/version.c1
-rw-r--r--lib/xfrm/ae.c985
-rw-r--r--lib/xfrm/lifetime.c275
-rw-r--r--lib/xfrm/sa.c2233
-rw-r--r--lib/xfrm/selector.c353
-rw-r--r--lib/xfrm/sp.c1436
-rw-r--r--lib/xfrm/template.c341
-rw-r--r--libnl-3.sym365
-rw-r--r--libnl-cli-3.sym117
-rw-r--r--libnl-genl-3.sym51
-rw-r--r--libnl-idiag-3.sym109
-rw-r--r--libnl-nf-3.sym316
-rw-r--r--libnl-route-3.sym1152
-rw-r--r--libnl-xfrm-3.0.pc.in11
-rw-r--r--libnl-xfrm-3.sym246
-rw-r--r--libnl.sym.in9
-rw-r--r--m4/ax_pkg_swig.m4135
-rw-r--r--m4/ax_python.m497
-rw-r--r--m4/ax_python_devel.m4325
-rw-r--r--m4/ax_swig_python.m464
-rw-r--r--make.log355
-rw-r--r--man/Makefile.am7
-rw-r--r--python/Makefile.am3
-rw-r--r--python/doc/Makefile.am8
-rw-r--r--python/examples/Makefile.am6
-rw-r--r--python/netlink/Makefile.am11
-rw-r--r--python/netlink/capi.i20
-rw-r--r--python/netlink/genl/Makefile.am5
-rw-r--r--python/netlink/genl/capi.i8
-rw-r--r--python/netlink/route/Makefile.am14
-rw-r--r--python/netlink/utils.h2
-rw-r--r--python/setup.py.in4
-rw-r--r--python/tests/Makefile.am5
-rw-r--r--src/.gitignore33
-rw-r--r--src/Makefile.am106
-rw-r--r--src/genl-ctrl-list.c13
-rw-r--r--src/idiag-socket-details.c3
-rw-r--r--src/lib/Makefile.am45
-rw-r--r--src/lib/addr.c1
-rw-r--r--src/lib/class.c1
-rw-r--r--src/lib/cls.c1
-rw-r--r--src/lib/ct.c1
-rw-r--r--src/lib/exp.c1
-rw-r--r--src/lib/link.c18
-rw-r--r--src/lib/neigh.c1
-rw-r--r--src/lib/qdisc.c1
-rw-r--r--src/lib/route.c19
-rw-r--r--src/lib/rule.c1
-rw-r--r--src/lib/tc.c1
-rw-r--r--src/lib/utils.c68
-rw-r--r--src/nf-ct-add.c5
-rw-r--r--src/nf-ct-events.c116
-rw-r--r--src/nf-ct-list.c13
-rw-r--r--src/nf-exp-add.c47
-rw-r--r--src/nf-exp-delete.c31
-rw-r--r--src/nf-exp-list.c15
-rw-r--r--src/nf-log.c10
-rw-r--r--src/nf-monitor.c4
-rw-r--r--src/nf-queue.c8
-rw-r--r--src/nl-addr-add.c15
-rw-r--r--src/nl-addr-delete.c7
-rw-r--r--src/nl-addr-list.c3
-rw-r--r--src/nl-class-add.c15
-rw-r--r--src/nl-class-delete.c13
-rw-r--r--src/nl-class-list.c15
-rw-r--r--src/nl-classid-lookup.c6
-rw-r--r--src/nl-cls-add.c17
-rw-r--r--src/nl-cls-delete.c17
-rw-r--r--src/nl-cls-list.c17
-rw-r--r--src/nl-fib-lookup.c3
-rw-r--r--src/nl-link-enslave.c3
-rw-r--r--src/nl-link-ifindex2name.c3
-rw-r--r--src/nl-link-list.c3
-rw-r--r--src/nl-link-name2ifindex.c3
-rw-r--r--src/nl-link-release.c3
-rw-r--r--src/nl-link-set.c4
-rw-r--r--src/nl-link-stats.c7
-rw-r--r--src/nl-list-caches.c1
-rw-r--r--src/nl-list-sockets.c3
-rw-r--r--src/nl-monitor.c119
-rw-r--r--src/nl-neigh-add.c15
-rw-r--r--src/nl-neigh-delete.c13
-rw-r--r--src/nl-neigh-list.c20
-rw-r--r--src/nl-neightbl-list.c15
-rw-r--r--src/nl-pktloc-lookup.c6
-rw-r--r--src/nl-qdisc-add.c15
-rw-r--r--src/nl-qdisc-delete.c13
-rw-r--r--src/nl-qdisc-list.c14
-rw-r--r--src/nl-route-add.c3
-rw-r--r--src/nl-route-delete.c3
-rw-r--r--src/nl-route-get.c10
-rw-r--r--src/nl-route-list.c3
-rw-r--r--src/nl-rule-list.c7
-rw-r--r--src/nl-tctree-list.c9
-rw-r--r--src/nl-util-addr.c1
-rw-r--r--tests/.gitignore10
-rw-r--r--tests/Makefile.am67
-rw-r--r--tests/check-addr.c2
-rw-r--r--tests/check-all.c4
-rw-r--r--tests/check-attr.c2
-rw-r--r--tests/check-ematch-tree-clone.c143
-rw-r--r--tests/test-cache-mngr.c2
-rw-r--r--tests/test-complex-HTB-with-hash-filters.c28
-rw-r--r--tests/test-create-bond.c2
-rw-r--r--tests/test-create-bridge.c12
-rw-r--r--tests/test-create-geneve.c87
-rw-r--r--tests/test-create-ifb.c31
-rw-r--r--tests/test-create-ipgretap.c56
-rw-r--r--tests/test-create-ipvlan.c47
-rw-r--r--tests/test-create-macsec.c51
-rw-r--r--tests/test-create-macvlan.c4
-rw-r--r--tests/test-create-macvtap.c52
-rw-r--r--tests/test-create-veth.c2
-rw-r--r--tests/test-create-vlan.c2
-rw-r--r--tests/test-create-vrf.c61
-rw-r--r--tests/test-create-vxlan.c2
-rw-r--r--tests/test-create-xfrmi.c49
-rw-r--r--tests/test-delete-link.c2
-rw-r--r--tests/test-genl.c4
-rw-r--r--tests/test-loopback-up-down.c54
-rw-r--r--tests/test-nf-cache-mngr.c2
-rw-r--r--tests/test-u32-filter-with-actions.c40
-rw-r--r--tests/util.h5
-rwxr-xr-xtools/build_release.sh86
397 files changed, 33061 insertions, 5183 deletions
diff --git a/.gitignore b/.gitignore
index 5f5f1ccb..c22a603c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ Makefile.in
defs.h.in
defs.h.in~
/lib/stamp-h1
+test-suite.log
/libnl-1.pc
/lib/defs.h
@@ -24,4 +25,3 @@ cscope.*
/configure
/libtool
/*.pc
-/libnl.sym
diff --git a/.indent.pro b/.indent.pro
new file mode 100644
index 00000000..ee5d177e
--- /dev/null
+++ b/.indent.pro
@@ -0,0 +1 @@
+-linux -il0 -cs -lp -cbi0
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 00000000..efc8ae5a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,8 @@
+language: c
+compiler:
+ - gcc
+ - clang
+
+before_install:
+
+script: ./.travis/run.sh
diff --git a/.travis/run.sh b/.travis/run.sh
new file mode 100755
index 00000000..afa17020
--- /dev/null
+++ b/.travis/run.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+CFLAGS="-Werror -Wall -Wdeclaration-after-statement -Wvla"
+
+if [ "$CC" = "clang" ]; then
+ CFLAGS="$CFLAGS -Wno-error=unused-command-line-argument -Wno-error=unused-function"
+fi
+
+CFLAGS="$CFLAGS -DNL_MORE_ASSERTS=1000"
+
+export CFLAGS
+./autogen.sh
+./configure
+make -j 5
+make -j 5 check
diff --git a/Android.bp b/Android.bp
index 0f6aec68..c9ca0edd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,8 +1,45 @@
+package {
+ default_applicable_licenses: ["external_libnl_license"],
+}
+
+// Added automatically by a large-scale-change that took the approach of
+// 'apply every license found to every target'. While this makes sure we respect
+// every license restriction, it may not be entirely correct.
+//
+// e.g. GPL in an MIT project might only apply to the contrib/ directory.
+//
+// Please consider splitting the single license below into multiple licenses,
+// taking care not to lose any license_kind information, and overriding the
+// default license using the 'licenses: [...]' property on targets as needed.
+//
+// For unused files, consider creating a 'fileGroup' with "//visibility:private"
+// to attach the license to, and including a comment whether the files may be
+// used in the current project.
+// See: http://go/android-license-faq
+license {
+ name: "external_libnl_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-BSD",
+ "SPDX-license-identifier-GPL",
+ "SPDX-license-identifier-GPL-2.0",
+ "SPDX-license-identifier-GPL-3.0",
+ "SPDX-license-identifier-LGPL",
+ "SPDX-license-identifier-LGPL-2.1",
+ "SPDX-license-identifier-LGPL-3.0",
+ "legacy_unencumbered",
+ ],
+ license_text: [
+ "COPYING",
+ ],
+}
+
cc_library {
name: "libnl",
host_supported: true,
vendor_available: true,
+ product_available: true,
vndk: {
enabled: true,
},
@@ -11,39 +48,28 @@ cc_library {
darwin: {
enabled: false,
},
+ linux_glibc: {
+ local_include_dirs: [
+ "include/linux-private",
+ ],
+ },
},
srcs: [
- "lib/cache.c",
- "lib/data.c",
- "lib/nl.c",
- "lib/cache_mngr.c",
- "lib/addr.c",
- "lib/socket.c",
+ "lib/*.c",
"lib/fib_lookup/lookup.c",
"lib/fib_lookup/request.c",
- "lib/msg.c",
- "lib/object.c",
- "lib/attr.c",
- "lib/utils.c",
- "lib/cache_mngt.c",
- "lib/handlers.c",
"lib/genl/ctrl.c",
- "lib/genl/mngt.c",
"lib/genl/family.c",
"lib/genl/genl.c",
- "lib/route/rtnl.c",
- "lib/route/route_utils.c",
+ "lib/genl/mngt.c",
"lib/netfilter/nfnl.c",
- "lib/error.c",
- "lib/version.c",
- "lib/hash.c",
- "lib/hashtable.c",
+ "lib/route/route_utils.c",
+ "lib/route/rtnl.c",
],
local_include_dirs: [
"include",
- "include/linux-private",
],
export_include_dirs: ["include"],
cflags: [
@@ -63,5 +89,8 @@ cc_library {
sanitize: {
integer_overflow: true,
},
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.virt",
+ ],
}
-
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 00000000..d24842f3
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+COPYING \ No newline at end of file
diff --git a/METADATA b/METADATA
new file mode 100644
index 00000000..536465db
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "libnl"
+description: "Netlink Library Suite"
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://github.com/thom311/libnl"
+ }
+ url {
+ type: GIT
+ value: "https://github.com/thom311/libnl.git"
+ }
+ version: "libnl3_5_0"
+ license_type: RESTRICTED
+ last_upgrade_date {
+ year: 2020
+ month: 3
+ day: 10
+ }
+}
diff --git a/Makefile.am b/Makefile.am
index bc4266de..b2e87379 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,21 +2,1022 @@
ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = include lib man python tests
+lib_LTLIBRARIES =
+noinst_LTLIBRARIES =
+check_LTLIBRARIES =
-pkgconfig_DATA = libnl-3.0.pc \
- libnl-route-3.0.pc \
- libnl-genl-3.0.pc \
- libnl-nf-3.0.pc
+check_PROGRAMS =
+check_programs =
+
+bin_PROGRAMS =
+sbin_PROGRAMS =
+noinst_PROGRAMS =
+
+TESTS =
+
+CLEANFILES =
+EXTRA_DIST =
+
+DISTCHECK_CONFIGURE_FLAGS = \
+ --disable-dependency-tracking
+
+pkgconfig_DATA = \
+ libnl-3.0.pc \
+ libnl-genl-3.0.pc \
+ libnl-idiag-3.0.pc \
+ libnl-nf-3.0.pc \
+ libnl-route-3.0.pc \
+ libnl-xfrm-3.0.pc \
+ $(NULL)
+
+warn_cppflags = \
+ -Wall \
+ -Wextra \
+ -Wmissing-prototypes \
+ -Wno-unused-parameter \
+ -Wno-sign-compare \
+ -Wno-missing-field-initializers \
+ -Wpointer-arith \
+ $(NULL)
+
+###############################################################################
+
+libnlincludedir = $(includedir)/libnl@MAJ_VERSION@
+
+libnlinclude_netlinkdir = $(libnlincludedir)/netlink
+libnlinclude_netlink_HEADERS = \
+ include/netlink/addr.h \
+ include/netlink/attr.h \
+ include/netlink/cache-api.h \
+ include/netlink/cache.h \
+ include/netlink/data.h \
+ include/netlink/errno.h \
+ include/netlink/handlers.h \
+ include/netlink/hash.h \
+ include/netlink/hashtable.h \
+ include/netlink/list.h \
+ include/netlink/msg.h \
+ include/netlink/netlink-compat.h \
+ include/netlink/netlink-kernel.h \
+ include/netlink/netlink.h \
+ include/netlink/object-api.h \
+ include/netlink/object.h \
+ include/netlink/socket.h \
+ include/netlink/types.h \
+ include/netlink/utils.h \
+ include/netlink/version.h \
+ $(NULL)
+libnlinclude_netlink_fib_lookupdir = $(libnlincludedir)/netlink/fib_lookup
+libnlinclude_netlink_fib_lookup_HEADERS = \
+ include/netlink/fib_lookup/lookup.h \
+ include/netlink/fib_lookup/request.h \
+ $(NULL)
+libnlinclude_netlink_genldir = $(libnlincludedir)/netlink/genl
+libnlinclude_netlink_genl_HEADERS = \
+ include/netlink/genl/ctrl.h \
+ include/netlink/genl/family.h \
+ include/netlink/genl/genl.h \
+ include/netlink/genl/mngt.h \
+ $(NULL)
+libnlinclude_netlink_idiagdir = $(libnlincludedir)/netlink/idiag
+libnlinclude_netlink_idiag_HEADERS = \
+ include/netlink/idiag/idiagnl.h \
+ include/netlink/idiag/meminfo.h \
+ include/netlink/idiag/msg.h \
+ include/netlink/idiag/req.h \
+ include/netlink/idiag/vegasinfo.h \
+ $(NULL)
+libnlinclude_netlink_netfilterdir = $(libnlincludedir)/netlink/netfilter
+libnlinclude_netlink_netfilter_HEADERS = \
+ include/netlink/netfilter/ct.h \
+ include/netlink/netfilter/exp.h \
+ include/netlink/netfilter/log.h \
+ include/netlink/netfilter/log_msg.h \
+ include/netlink/netfilter/netfilter.h \
+ include/netlink/netfilter/nfnl.h \
+ include/netlink/netfilter/queue.h \
+ include/netlink/netfilter/queue_msg.h \
+ $(NULL)
+libnlinclude_netlink_routedir = $(libnlincludedir)/netlink/route
+libnlinclude_netlink_route_HEADERS = \
+ include/netlink/route/action.h \
+ include/netlink/route/addr.h \
+ include/netlink/route/class.h \
+ include/netlink/route/classifier.h \
+ include/netlink/route/link.h \
+ include/netlink/route/neighbour.h \
+ include/netlink/route/neightbl.h \
+ include/netlink/route/netconf.h \
+ include/netlink/route/nexthop.h \
+ include/netlink/route/pktloc.h \
+ include/netlink/route/qdisc.h \
+ include/netlink/route/route.h \
+ include/netlink/route/rtnl.h \
+ include/netlink/route/rule.h \
+ include/netlink/route/tc-api.h \
+ include/netlink/route/tc.h \
+ $(NULL)
+libnlinclude_netlink_route_actdir = $(libnlincludedir)/netlink/route/act
+libnlinclude_netlink_route_act_HEADERS = \
+ include/netlink/route/act/gact.h \
+ include/netlink/route/act/mirred.h \
+ include/netlink/route/act/skbedit.h \
+ include/netlink/route/act/vlan.h \
+ $(NULL)
+libnlinclude_netlink_route_clsdir = $(libnlincludedir)/netlink/route/cls
+libnlinclude_netlink_route_cls_HEADERS = \
+ include/netlink/route/cls/basic.h \
+ include/netlink/route/cls/cgroup.h \
+ include/netlink/route/cls/ematch.h \
+ include/netlink/route/cls/fw.h \
+ include/netlink/route/cls/matchall.h \
+ include/netlink/route/cls/police.h \
+ include/netlink/route/cls/u32.h \
+ $(NULL)
+libnlinclude_netlink_route_cls_ematchdir = $(libnlincludedir)/netlink/route/cls/ematch
+libnlinclude_netlink_route_cls_ematch_HEADERS = \
+ include/netlink/route/cls/ematch/cmp.h \
+ include/netlink/route/cls/ematch/meta.h \
+ include/netlink/route/cls/ematch/nbyte.h \
+ include/netlink/route/cls/ematch/text.h \
+ $(NULL)
+libnlinclude_netlink_route_linkdir = $(libnlincludedir)/netlink/route/link
+libnlinclude_netlink_route_link_HEADERS = \
+ include/netlink/route/link/api.h \
+ include/netlink/route/link/bonding.h \
+ include/netlink/route/link/bridge.h \
+ include/netlink/route/link/can.h \
+ include/netlink/route/link/geneve.h \
+ include/netlink/route/link/inet.h \
+ include/netlink/route/link/inet6.h \
+ include/netlink/route/link/info-api.h \
+ include/netlink/route/link/ip6tnl.h \
+ include/netlink/route/link/ipgre.h \
+ include/netlink/route/link/ipip.h \
+ include/netlink/route/link/ipvlan.h \
+ include/netlink/route/link/ipvti.h \
+ include/netlink/route/link/macsec.h \
+ include/netlink/route/link/macvlan.h \
+ include/netlink/route/link/macvtap.h \
+ include/netlink/route/link/ppp.h \
+ include/netlink/route/link/sit.h \
+ include/netlink/route/link/sriov.h \
+ include/netlink/route/link/veth.h \
+ include/netlink/route/link/vlan.h \
+ include/netlink/route/link/vrf.h \
+ include/netlink/route/link/vxlan.h \
+ include/netlink/route/link/xfrmi.h \
+ $(NULL)
+libnlinclude_netlink_route_qdiscdir = $(libnlincludedir)/netlink/route/qdisc
+libnlinclude_netlink_route_qdisc_HEADERS = \
+ include/netlink/route/qdisc/cbq.h \
+ include/netlink/route/qdisc/dsmark.h \
+ include/netlink/route/qdisc/fifo.h \
+ include/netlink/route/qdisc/fq_codel.h \
+ include/netlink/route/qdisc/hfsc.h \
+ include/netlink/route/qdisc/htb.h \
+ include/netlink/route/qdisc/mqprio.h \
+ include/netlink/route/qdisc/netem.h \
+ include/netlink/route/qdisc/plug.h \
+ include/netlink/route/qdisc/prio.h \
+ include/netlink/route/qdisc/red.h \
+ include/netlink/route/qdisc/sfq.h \
+ include/netlink/route/qdisc/tbf.h \
+ $(NULL)
+libnlinclude_netlink_xfrmdir = $(libnlincludedir)/netlink/xfrm
+libnlinclude_netlink_xfrm_HEADERS = \
+ include/netlink/xfrm/ae.h \
+ include/netlink/xfrm/lifetime.h \
+ include/netlink/xfrm/sa.h \
+ include/netlink/xfrm/selector.h \
+ include/netlink/xfrm/sp.h \
+ include/netlink/xfrm/template.h \
+ $(NULL)
if ENABLE_CLI
-SUBDIRS += src
-pkgconfig_DATA += libnl-cli-3.0.pc
+libnlinclude_netlink_clidir = $(libnlincludedir)/netlink/cli
+libnlinclude_netlink_cli_HEADERS = \
+ include/netlink/cli/addr.h \
+ include/netlink/cli/class.h \
+ include/netlink/cli/cls.h \
+ include/netlink/cli/ct.h \
+ include/netlink/cli/exp.h \
+ include/netlink/cli/link.h \
+ include/netlink/cli/neigh.h \
+ include/netlink/cli/qdisc.h \
+ include/netlink/cli/route.h \
+ include/netlink/cli/rule.h \
+ include/netlink/cli/tc.h \
+ include/netlink/cli/utils.h \
+ $(NULL)
endif
+noinst_HEADERS = \
+ include/linux-private/linux/can/netlink.h \
+ include/linux-private/linux/fib_rules.h \
+ include/linux-private/linux/gen_stats.h \
+ include/linux-private/linux/genetlink.h \
+ include/linux-private/linux/if.h \
+ include/linux-private/linux/if_addr.h \
+ include/linux-private/linux/if_arp.h \
+ include/linux-private/linux/if_bridge.h \
+ include/linux-private/linux/if_ether.h \
+ include/linux-private/linux/if_link.h \
+ include/linux-private/linux/if_macsec.h \
+ include/linux-private/linux/if_tunnel.h \
+ include/linux-private/linux/if_vlan.h \
+ include/linux-private/linux/in.h \
+ include/linux-private/linux/in6.h \
+ include/linux-private/linux/inet_diag.h \
+ include/linux-private/linux/ip.h \
+ include/linux-private/linux/ipv6.h \
+ include/linux-private/linux/libc-compat.h \
+ include/linux-private/linux/lwtunnel.h \
+ include/linux-private/linux/mpls.h \
+ include/linux-private/linux/mpls_iptunnel.h \
+ include/linux-private/linux/neighbour.h \
+ include/linux-private/linux/netconf.h \
+ include/linux-private/linux/netfilter.h \
+ include/linux-private/linux/netfilter/nf_conntrack_common.h \
+ include/linux-private/linux/netfilter/nfnetlink.h \
+ include/linux-private/linux/netfilter/nfnetlink_compat.h \
+ include/linux-private/linux/netfilter/nfnetlink_conntrack.h \
+ include/linux-private/linux/netfilter/nfnetlink_log.h \
+ include/linux-private/linux/netfilter/nfnetlink_queue.h \
+ include/linux-private/linux/netlink.h \
+ include/linux-private/linux/pkt_cls.h \
+ include/linux-private/linux/pkt_sched.h \
+ include/linux-private/linux/rtnetlink.h \
+ include/linux-private/linux/snmp.h \
+ include/linux-private/linux/sock_diag.h \
+ include/linux-private/linux/socket.h \
+ include/linux-private/linux/tc_act/tc_gact.h \
+ include/linux-private/linux/tc_act/tc_mirred.h \
+ include/linux-private/linux/tc_act/tc_skbedit.h \
+ include/linux-private/linux/tc_act/tc_vlan.h \
+ include/linux-private/linux/tc_ematch/tc_em_meta.h \
+ include/linux-private/linux/veth.h \
+ include/linux-private/linux/xfrm.h \
+ include/netlink-private/cache-api.h \
+ include/netlink-private/genl.h \
+ include/netlink-private/netlink.h \
+ include/netlink-private/object-api.h \
+ include/netlink-private/route/link/api.h \
+ include/netlink-private/route/link/sriov.h \
+ include/netlink-private/route/mpls.h \
+ include/netlink-private/route/nexthop-encap.h \
+ include/netlink-private/route/tc-api.h \
+ include/netlink-private/socket.h \
+ include/netlink-private/tc.h \
+ include/netlink-private/types.h \
+ include/netlink-private/utils.h \
+ $(NULL)
+
+###############################################################################
+
+# Hack to avoid using ylwrap. It does not function correctly in combination
+# with --header-file=
+
+lib/route/pktloc_grammar.h: lib/route/pktloc_grammar.c
+ @true
+
+lib/route/pktloc_grammar.c: lib/route/pktloc_grammar.l lib/route/.dirstamp
+ $(AM_V_GEN) $(FLEX) --header-file=lib/route/pktloc_grammar.h $(LFLAGS) -o $@ $<
+
+lib/route/pktloc_syntax.h: lib/route/pktloc_syntax.c
+ @true
+
+lib/route/pktloc_syntax.c: lib/route/pktloc_syntax.y lib/route/.dirstamp
+ $(AM_V_GEN) $(YACC) -d $(YFLAGS) -o $@ $<
+
+lib/route/cls/ematch_grammar.h: lib/route/cls/ematch_grammar.c
+ @true
+
+lib/route/cls/ematch_grammar.c: lib/route/cls/ematch_grammar.l lib/route/cls/.dirstamp
+ $(AM_V_GEN) $(FLEX) --header-file=lib/route/cls/ematch_grammar.h $(LFLAGS) -o $@ $<
+
+lib/route/cls/ematch_syntax.h: lib/route/cls/ematch_syntax.c
+ @true
+
+lib/route/cls/ematch_syntax.c: lib/route/cls/ematch_syntax.y lib/route/cls/.dirstamp
+ $(AM_V_GEN) $(YACC) -d $(YFLAGS) -o $@ $<
+
+grammar_files_sources = \
+ lib/route/cls/ematch_grammar.c \
+ lib/route/cls/ematch_syntax.c \
+ lib/route/pktloc_grammar.c \
+ lib/route/pktloc_syntax.c \
+ $(NULL)
+
+grammar_files_headers = $(grammar_files_sources:%.c=%.h)
+
+CLEANFILES += \
+ $(grammar_files_sources) \
+ $(grammar_files_headers)
+
+EXTRA_DIST += \
+ lib/route/cls/ematch_grammar.l \
+ lib/route/cls/ematch_syntax.y \
+ lib/route/pktloc_grammar.l \
+ lib/route/pktloc_syntax.y \
+ $(NULL)
+
+###############################################################################
+
+lib_cppflags = \
+ $(warn_cppflags) \
+ -D_GNU_SOURCE \
+ -DSYSCONFDIR=\"$(sysconfdir)/libnl\" \
+ -I$(srcdir)/include/linux-private \
+ -I$(srcdir)/include \
+ -I$(builddir)/include \
+ -I$(builddir)/lib/route \
+ -I$(builddir)/lib/route/cls
+
+lib_LTLIBRARIES += lib/libnl-3.la
+
+lib_libnl_3_la_SOURCES = \
+ lib/addr.c \
+ lib/attr.c \
+ lib/cache.c \
+ lib/cache_mngr.c \
+ lib/cache_mngt.c \
+ lib/data.c \
+ lib/error.c \
+ lib/handlers.c \
+ lib/hash.c \
+ lib/hashtable.c \
+ lib/mpls.c \
+ lib/msg.c \
+ lib/nl.c \
+ lib/object.c \
+ lib/socket.c \
+ lib/utils.c \
+ lib/version.c \
+ $(NULL)
+EXTRA_lib_libnl_3_la_DEPENDENCIES = \
+ libnl-3.sym
+lib_libnl_3_la_CPPFLAGS = \
+ $(lib_cppflags)
+lib_libnl_3_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -Wl,--version-script=$(srcdir)/libnl-3.sym
+
+lib_LTLIBRARIES += lib/libnl-route-3.la
+
+lib_libnl_route_3_la_SOURCES = \
+ lib/fib_lookup/lookup.c \
+ lib/fib_lookup/request.c \
+ lib/route/act.c \
+ lib/route/act/gact.c \
+ lib/route/act/mirred.c \
+ lib/route/act/skbedit.c \
+ lib/route/act/vlan.c \
+ lib/route/addr.c \
+ lib/route/class.c \
+ lib/route/classid.c \
+ lib/route/cls.c \
+ lib/route/cls/basic.c \
+ lib/route/cls/cgroup.c \
+ lib/route/cls/ematch.c \
+ lib/route/cls/ematch/cmp.c \
+ lib/route/cls/ematch/container.c \
+ lib/route/cls/ematch/meta.c \
+ lib/route/cls/ematch/nbyte.c \
+ lib/route/cls/ematch/text.c \
+ lib/route/cls/fw.c \
+ lib/route/cls/mall.c \
+ lib/route/cls/police.c \
+ lib/route/cls/u32.c \
+ lib/route/link.c \
+ lib/route/link/api.c \
+ lib/route/link/bonding.c \
+ lib/route/link/bridge.c \
+ lib/route/link/can.c \
+ lib/route/link/dummy.c \
+ lib/route/link/geneve.c \
+ lib/route/link/ifb.c \
+ lib/route/link/inet.c \
+ lib/route/link/inet6.c \
+ lib/route/link/ip6tnl.c \
+ lib/route/link/ipgre.c \
+ lib/route/link/ipip.c \
+ lib/route/link/ipvlan.c \
+ lib/route/link/ipvti.c \
+ lib/route/link/macsec.c \
+ lib/route/link/macvlan.c \
+ lib/route/link/ppp.c \
+ lib/route/link/sit.c \
+ lib/route/link/sriov.c \
+ lib/route/link/veth.c \
+ lib/route/link/vlan.c \
+ lib/route/link/vrf.c \
+ lib/route/link/vxlan.c \
+ lib/route/link/xfrmi.c \
+ lib/route/neigh.c \
+ lib/route/neightbl.c \
+ lib/route/netconf.c \
+ lib/route/nexthop.c \
+ lib/route/nexthop_encap.c \
+ lib/route/nh_encap_mpls.c \
+ lib/route/pktloc.c \
+ lib/route/qdisc.c \
+ lib/route/qdisc/blackhole.c \
+ lib/route/qdisc/cbq.c \
+ lib/route/qdisc/dsmark.c \
+ lib/route/qdisc/fifo.c \
+ lib/route/qdisc/fq_codel.c \
+ lib/route/qdisc/hfsc.c \
+ lib/route/qdisc/htb.c \
+ lib/route/qdisc/ingress.c \
+ lib/route/qdisc/mqprio.c \
+ lib/route/qdisc/netem.c \
+ lib/route/qdisc/plug.c \
+ lib/route/qdisc/prio.c \
+ lib/route/qdisc/red.c \
+ lib/route/qdisc/sfq.c \
+ lib/route/qdisc/tbf.c \
+ lib/route/route.c \
+ lib/route/route_obj.c \
+ lib/route/route_utils.c \
+ lib/route/rtnl.c \
+ lib/route/rule.c \
+ lib/route/tc.c \
+ $(NULL)
+nodist_lib_libnl_route_3_la_SOURCES = \
+ $(grammar_files_sources)
+EXTRA_lib_libnl_route_3_la_DEPENDENCIES = \
+ libnl-route-3.sym
+lib_libnl_route_3_la_CPPFLAGS = \
+ $(lib_cppflags)
+lib_libnl_route_3_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -Wl,--version-script=$(srcdir)/libnl-route-3.sym
+lib_libnl_route_3_la_LIBADD = \
+ lib/libnl-3.la
+
+$(lib_libnl_route_3_la_OBJECTS): $(grammar_files_headers)
+
+lib_LTLIBRARIES += lib/libnl-idiag-3.la
+
+lib_libnl_idiag_3_la_SOURCES = \
+ lib/idiag/idiag.c \
+ lib/idiag/idiag_meminfo_obj.c \
+ lib/idiag/idiag_msg_obj.c \
+ lib/idiag/idiag_req_obj.c \
+ lib/idiag/idiag_vegasinfo_obj.c \
+ $(NULL)
+EXTRA_lib_libnl_idiag_3_la_DEPENDENCIES = \
+ libnl-idiag-3.sym
+lib_libnl_idiag_3_la_CPPFLAGS = \
+ $(lib_cppflags)
+lib_libnl_idiag_3_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -Wl,--version-script=$(srcdir)/libnl-idiag-3.sym
+lib_libnl_idiag_3_la_LIBADD = \
+ lib/libnl-3.la
+
+lib_LTLIBRARIES += lib/libnl-genl-3.la
+
+lib_libnl_genl_3_la_SOURCES = \
+ lib/genl/ctrl.c \
+ lib/genl/family.c \
+ lib/genl/genl.c \
+ lib/genl/mngt.c \
+ $(NULL)
+EXTRA_lib_libnl_genl_3_la_DEPENDENCIES = \
+ libnl-genl-3.sym
+lib_libnl_genl_3_la_CPPFLAGS = \
+ $(lib_cppflags)
+lib_libnl_genl_3_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -Wl,--version-script=$(srcdir)/libnl-genl-3.sym
+lib_libnl_genl_3_la_LIBADD = \
+ lib/libnl-3.la
+
+lib_LTLIBRARIES += lib/libnl-nf-3.la
+
+lib_libnl_nf_3_la_SOURCES = \
+ lib/netfilter/ct.c \
+ lib/netfilter/ct_obj.c \
+ lib/netfilter/exp.c \
+ lib/netfilter/exp_obj.c \
+ lib/netfilter/log.c \
+ lib/netfilter/log_msg.c \
+ lib/netfilter/log_msg_obj.c \
+ lib/netfilter/log_obj.c \
+ lib/netfilter/netfilter.c \
+ lib/netfilter/nfnl.c \
+ lib/netfilter/queue.c \
+ lib/netfilter/queue_msg.c \
+ lib/netfilter/queue_msg_obj.c \
+ lib/netfilter/queue_obj.c \
+ $(NULL)
+lib_libnl_nf_3_la_CPPFLAGS = \
+ $(lib_cppflags)
+EXTRA_lib_libnl_nf_3_la_DEPENDENCIES = \
+ libnl-nf-3.sym
+lib_libnl_nf_3_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -Wl,--version-script=$(srcdir)/libnl-nf-3.sym
+lib_libnl_nf_3_la_LIBADD = \
+ lib/libnl-3.la \
+ lib/libnl-route-3.la
+
+lib_LTLIBRARIES += lib/libnl-xfrm-3.la
+
+lib_libnl_xfrm_3_la_SOURCES = \
+ lib/xfrm/ae.c \
+ lib/xfrm/lifetime.c \
+ lib/xfrm/sa.c \
+ lib/xfrm/selector.c \
+ lib/xfrm/sp.c \
+ lib/xfrm/template.c \
+ $(NULL)
+lib_libnl_xfrm_3_la_CPPFLAGS = \
+ $(lib_cppflags)
+lib_libnl_xfrm_3_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -Wl,--version-script=$(srcdir)/libnl-xfrm-3.sym
+EXTRA_lib_libnl_xfrm_3_la_DEPENDENCIES = \
+ libnl-xfrm-3.sym
+lib_libnl_xfrm_3_la_LIBADD = \
+ lib/libnl-3.la
+
+lib_cli_ltlibraries_cls = \
+ lib/cli/cls/basic.la \
+ lib/cli/cls/cgroup.la \
+ $(NULL)
+lib_cli_ltlibraries_qdisc = \
+ lib/cli/qdisc/bfifo.la \
+ lib/cli/qdisc/blackhole.la \
+ lib/cli/qdisc/fq_codel.la \
+ lib/cli/qdisc/hfsc.la \
+ lib/cli/qdisc/htb.la \
+ lib/cli/qdisc/ingress.la \
+ lib/cli/qdisc/pfifo.la \
+ lib/cli/qdisc/plug.la \
+ $(NULL)
+
+if ENABLE_CLI
+pkglib_clsdir = $(pkglibdir)/cli/cls
+pkglib_qdiscdir = $(pkglibdir)/cli/qdisc
+pkglib_cls_LTLIBRARIES = $(lib_cli_ltlibraries_cls)
+pkglib_qdisc_LTLIBRARIES = $(lib_cli_ltlibraries_qdisc)
+else
+check_LTLIBRARIES += \
+ $(lib_cli_ltlibraries_cls) \
+ $(lib_cli_ltlibraries_qdisc)
+endif
+
+lib_cli_ldflags = \
+ -module -avoid-version
+
+lib_cli_cls_basic_la_CPPFLAGS = $(lib_cppflags)
+lib_cli_cls_basic_la_LDFLAGS = $(lib_cli_ldflags)
+lib_cli_cls_cgroup_la_CPPFLAGS = $(lib_cppflags)
+lib_cli_cls_cgroup_la_LDFLAGS = $(lib_cli_ldflags)
+lib_cli_qdisc_bfifo_la_CPPFLAGS = $(lib_cppflags)
+lib_cli_qdisc_bfifo_la_LDFLAGS = $(lib_cli_ldflags)
+lib_cli_qdisc_blackhole_la_CPPFLAGS = $(lib_cppflags)
+lib_cli_qdisc_blackhole_la_LDFLAGS = $(lib_cli_ldflags)
+lib_cli_qdisc_fq_codel_la_CPPFLAGS = $(lib_cppflags)
+lib_cli_qdisc_fq_codel_la_LDFLAGS = $(lib_cli_ldflags)
+lib_cli_qdisc_hfsc_la_CPPFLAGS = $(lib_cppflags)
+lib_cli_qdisc_hfsc_la_LDFLAGS = $(lib_cli_ldflags)
+lib_cli_qdisc_htb_la_CPPFLAGS = $(lib_cppflags)
+lib_cli_qdisc_htb_la_LDFLAGS = $(lib_cli_ldflags)
+lib_cli_qdisc_ingress_la_CPPFLAGS = $(lib_cppflags)
+lib_cli_qdisc_ingress_la_LDFLAGS = $(lib_cli_ldflags)
+lib_cli_qdisc_pfifo_la_CPPFLAGS = $(lib_cppflags)
+lib_cli_qdisc_pfifo_la_LDFLAGS = $(lib_cli_ldflags)
+lib_cli_qdisc_plug_la_CPPFLAGS = $(lib_cppflags)
+lib_cli_qdisc_plug_la_LDFLAGS = $(lib_cli_ldflags)
+
+###############################################################################
+
+src_lib_ldflags =
+
+if ENABLE_CLI
+lib_LTLIBRARIES += src/lib/libnl-cli-3.la
+src_lib_ldflags += -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
+else
+check_LTLIBRARIES += src/lib/libnl-cli-3.la
+endif
+
+src_lib_libnl_cli_3_la_SOURCES = \
+ src/lib/addr.c \
+ src/lib/class.c \
+ src/lib/cls.c \
+ src/lib/ct.c \
+ src/lib/exp.c \
+ src/lib/link.c \
+ src/lib/neigh.c \
+ src/lib/qdisc.c \
+ src/lib/route.c \
+ src/lib/rule.c \
+ src/lib/tc.c \
+ src/lib/utils.c \
+ $(NULL)
+EXTRA_src_lib_libnl_cli_3_la_DEPENDENCIES = \
+ libnl-cli-3.sym
+src_lib_libnl_cli_3_la_CPPFLAGS = \
+ $(warn_cppflags) \
+ -D_GNU_SOURCE \
+ -DPKGLIBDIR=\"$(pkglibdir)\" \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -I$(srcdir)/include/linux-private \
+ -I$(srcdir)/include \
+ -I$(builddir)/include
+src_lib_libnl_cli_3_la_LDFLAGS = \
+ $(src_lib_ldflags) \
+ -Wl,--version-script=$(srcdir)/libnl-cli-3.sym
+src_lib_libnl_cli_3_la_LIBADD = \
+ lib/libnl-3.la \
+ lib/libnl-route-3.la \
+ lib/libnl-nf-3.la \
+ lib/libnl-genl-3.la \
+ -ldl \
+ $(NULL)
+
+###############################################################################
+
+src_cppflags = \
+ $(warn_cppflags) \
+ -D_GNU_SOURCE \
+ -DSYSCONFDIR=\"$(sysconfdir)/libnl\" \
+ -I$(srcdir)/include/linux-private \
+ -I$(srcdir)/include \
+ -I$(builddir)/include
+
+src_ldadd = \
+ src/lib/libnl-cli-3.la \
+ lib/libnl-3.la \
+ lib/libnl-nf-3.la \
+ lib/libnl-genl-3.la \
+ lib/libnl-route-3.la \
+ lib/libnl-idiag-3.la \
+ $(NULL)
+
+cli_programs = \
+ src/genl-ctrl-list \
+ src/idiag-socket-details \
+ src/nf-ct-add \
+ src/nf-ct-events \
+ src/nf-ct-list \
+ src/nf-exp-add \
+ src/nf-exp-delete \
+ src/nf-exp-list \
+ src/nf-log \
+ src/nf-monitor \
+ src/nf-queue \
+ src/nl-addr-add \
+ src/nl-addr-delete \
+ src/nl-addr-list \
+ src/nl-class-add \
+ src/nl-class-delete \
+ src/nl-class-list \
+ src/nl-classid-lookup \
+ src/nl-cls-add \
+ src/nl-cls-delete \
+ src/nl-cls-list \
+ src/nl-fib-lookup \
+ src/nl-link-enslave \
+ src/nl-link-ifindex2name \
+ src/nl-link-list \
+ src/nl-link-name2ifindex \
+ src/nl-link-release \
+ src/nl-link-set \
+ src/nl-link-stats \
+ src/nl-list-caches \
+ src/nl-list-sockets \
+ src/nl-monitor \
+ src/nl-neigh-add \
+ src/nl-neigh-delete \
+ src/nl-neigh-list \
+ src/nl-neightbl-list \
+ src/nl-pktloc-lookup \
+ src/nl-qdisc-add \
+ src/nl-qdisc-delete \
+ src/nl-qdisc-list \
+ src/nl-route-add \
+ src/nl-route-delete \
+ src/nl-route-get \
+ src/nl-route-list \
+ src/nl-rule-list \
+ src/nl-tctree-list \
+ src/nl-util-addr \
+ $(NULL)
+
+if ENABLE_CLI
+if ENABLE_CLI_INSTALL_BIN
+bin_PROGRAMS += $(cli_programs)
+else
+if ENABLE_CLI_INSTALL_SBIN
+sbin_PROGRAMS += $(cli_programs)
+else
+noinst_PROGRAMS += $(cli_programs)
+endif
+endif
+else
+check_PROGRAMS += $(cli_programs)
+endif
+
+src_genl_ctrl_list_CPPFLAGS = $(src_cppflags)
+src_genl_ctrl_list_LDADD = $(src_ldadd)
+src_idiag_socket_details_CPPFLAGS = $(src_cppflags)
+src_idiag_socket_details_LDADD = $(src_ldadd)
+src_nf_ct_add_CPPFLAGS = $(src_cppflags)
+src_nf_ct_add_LDADD = $(src_ldadd)
+src_nf_ct_events_CPPFLAGS = $(src_cppflags)
+src_nf_ct_events_LDADD = $(src_ldadd)
+src_nf_ct_list_CPPFLAGS = $(src_cppflags)
+src_nf_ct_list_LDADD = $(src_ldadd)
+src_nf_exp_add_CPPFLAGS = $(src_cppflags)
+src_nf_exp_add_LDADD = $(src_ldadd)
+src_nf_exp_delete_CPPFLAGS = $(src_cppflags)
+src_nf_exp_delete_LDADD = $(src_ldadd)
+src_nf_exp_list_CPPFLAGS = $(src_cppflags)
+src_nf_exp_list_LDADD = $(src_ldadd)
+src_nf_log_CPPFLAGS = $(src_cppflags)
+src_nf_log_LDADD = $(src_ldadd)
+src_nf_monitor_CPPFLAGS = $(src_cppflags)
+src_nf_monitor_LDADD = $(src_ldadd)
+src_nf_queue_CPPFLAGS = $(src_cppflags)
+src_nf_queue_LDADD = $(src_ldadd)
+src_nl_addr_add_CPPFLAGS = $(src_cppflags)
+src_nl_addr_add_LDADD = $(src_ldadd)
+src_nl_addr_delete_CPPFLAGS = $(src_cppflags)
+src_nl_addr_delete_LDADD = $(src_ldadd)
+src_nl_addr_list_CPPFLAGS = $(src_cppflags)
+src_nl_addr_list_LDADD = $(src_ldadd)
+src_nl_class_add_CPPFLAGS = $(src_cppflags)
+src_nl_class_add_LDADD = $(src_ldadd)
+src_nl_class_delete_CPPFLAGS = $(src_cppflags)
+src_nl_class_delete_LDADD = $(src_ldadd)
+src_nl_class_list_CPPFLAGS = $(src_cppflags)
+src_nl_class_list_LDADD = $(src_ldadd)
+src_nl_classid_lookup_CPPFLAGS = $(src_cppflags)
+src_nl_classid_lookup_LDADD = $(src_ldadd)
+src_nl_cls_add_CPPFLAGS = $(src_cppflags)
+src_nl_cls_add_LDADD = $(src_ldadd)
+src_nl_cls_delete_CPPFLAGS = $(src_cppflags)
+src_nl_cls_delete_LDADD = $(src_ldadd)
+src_nl_cls_list_CPPFLAGS = $(src_cppflags)
+src_nl_cls_list_LDADD = $(src_ldadd)
+src_nl_fib_lookup_CPPFLAGS = $(src_cppflags)
+src_nl_fib_lookup_LDADD = $(src_ldadd)
+src_nl_link_enslave_CPPFLAGS = $(src_cppflags)
+src_nl_link_enslave_LDADD = $(src_ldadd)
+src_nl_link_ifindex2name_CPPFLAGS = $(src_cppflags)
+src_nl_link_ifindex2name_LDADD = $(src_ldadd)
+src_nl_link_list_CPPFLAGS = $(src_cppflags)
+src_nl_link_list_LDADD = $(src_ldadd)
+src_nl_link_name2ifindex_CPPFLAGS = $(src_cppflags)
+src_nl_link_name2ifindex_LDADD = $(src_ldadd)
+src_nl_link_release_CPPFLAGS = $(src_cppflags)
+src_nl_link_release_LDADD = $(src_ldadd)
+src_nl_link_set_CPPFLAGS = $(src_cppflags)
+src_nl_link_set_LDADD = $(src_ldadd)
+src_nl_link_stats_CPPFLAGS = $(src_cppflags)
+src_nl_link_stats_LDADD = $(src_ldadd)
+src_nl_list_caches_CPPFLAGS = $(src_cppflags)
+src_nl_list_caches_LDADD = $(src_ldadd)
+src_nl_list_sockets_CPPFLAGS = $(src_cppflags)
+src_nl_list_sockets_LDADD = $(src_ldadd)
+src_nl_monitor_CPPFLAGS = $(src_cppflags)
+src_nl_monitor_LDADD = $(src_ldadd)
+src_nl_neigh_add_CPPFLAGS = $(src_cppflags)
+src_nl_neigh_add_LDADD = $(src_ldadd)
+src_nl_neigh_delete_CPPFLAGS = $(src_cppflags)
+src_nl_neigh_delete_LDADD = $(src_ldadd)
+src_nl_neigh_list_CPPFLAGS = $(src_cppflags)
+src_nl_neigh_list_LDADD = $(src_ldadd)
+src_nl_neightbl_list_CPPFLAGS = $(src_cppflags)
+src_nl_neightbl_list_LDADD = $(src_ldadd)
+src_nl_pktloc_lookup_CPPFLAGS = $(src_cppflags)
+src_nl_pktloc_lookup_LDADD = $(src_ldadd)
+src_nl_qdisc_add_CPPFLAGS = $(src_cppflags)
+src_nl_qdisc_add_LDADD = $(src_ldadd)
+src_nl_qdisc_delete_CPPFLAGS = $(src_cppflags)
+src_nl_qdisc_delete_LDADD = $(src_ldadd)
+src_nl_qdisc_list_CPPFLAGS = $(src_cppflags)
+src_nl_qdisc_list_LDADD = $(src_ldadd)
+src_nl_route_add_CPPFLAGS = $(src_cppflags)
+src_nl_route_add_LDADD = $(src_ldadd)
+src_nl_route_delete_CPPFLAGS = $(src_cppflags)
+src_nl_route_delete_LDADD = $(src_ldadd)
+src_nl_route_get_CPPFLAGS = $(src_cppflags)
+src_nl_route_get_LDADD = $(src_ldadd)
+src_nl_route_list_CPPFLAGS = $(src_cppflags)
+src_nl_route_list_LDADD = $(src_ldadd)
+src_nl_rule_list_CPPFLAGS = $(src_cppflags)
+src_nl_rule_list_LDADD = $(src_ldadd)
+src_nl_tctree_list_CPPFLAGS = $(src_cppflags)
+src_nl_tctree_list_LDADD = $(src_ldadd)
+src_nl_util_addr_CPPFLAGS = $(src_cppflags)
+src_nl_util_addr_LDADD = $(src_ldadd)
+
+###############################################################################
+
+tests_cppflags = \
+ $(warn_cppflags) \
+ -D_GNU_SOURCE \
+ -DSYSCONFDIR=\"$(sysconfdir)/libnl\" \
+ -I$(srcdir)/include/linux-private \
+ -I$(srcdir)/include \
+ -I$(builddir)/include
+
+tests_ldadd = \
+ lib/libnl-3.la \
+ lib/libnl-nf-3.la \
+ lib/libnl-genl-3.la \
+ lib/libnl-route-3.la
+
+check_PROGRAMS += \
+ tests/test-complex-HTB-with-hash-filters \
+ tests/test-create-bond \
+ tests/test-create-bridge \
+ tests/test-create-geneve \
+ tests/test-create-ifb \
+ tests/test-create-ip6tnl \
+ tests/test-create-ipgre \
+ tests/test-create-ipgretap \
+ tests/test-create-ipip \
+ tests/test-create-ipvlan \
+ tests/test-create-ipvti \
+ tests/test-create-macsec \
+ tests/test-create-macvlan \
+ tests/test-create-macvtap \
+ tests/test-create-sit \
+ tests/test-create-veth \
+ tests/test-create-vlan \
+ tests/test-create-vrf \
+ tests/test-create-vxlan \
+ tests/test-create-xfrmi \
+ tests/test-delete-link \
+ tests/test-loopback-up-down \
+ tests/test-socket-creation \
+ tests/test-u32-filter-with-actions \
+ $(NULL)
+
+tests_test_complex_HTB_with_hash_filters_CPPFLAGS = $(tests_cppflags)
+tests_test_complex_HTB_with_hash_filters_LDADD = $(tests_ldadd)
+tests_test_create_bond_CPPFLAGS = $(tests_cppflags)
+tests_test_create_bond_LDADD = $(tests_ldadd)
+tests_test_create_bridge_CPPFLAGS = $(tests_cppflags)
+tests_test_create_bridge_LDADD = $(tests_ldadd)
+tests_test_create_geneve_CPPFLAGS = $(tests_cppflags)
+tests_test_create_geneve_LDADD = $(tests_ldadd)
+tests_test_create_ifb_CPPFLAGS = $(tests_cppflags)
+tests_test_create_ifb_LDADD = $(tests_ldadd)
+tests_test_create_ip6tnl_CPPFLAGS = $(tests_cppflags)
+tests_test_create_ip6tnl_LDADD = $(tests_ldadd)
+tests_test_create_ipgre_CPPFLAGS = $(tests_cppflags)
+tests_test_create_ipgre_LDADD = $(tests_ldadd)
+tests_test_create_ipgretap_CPPFLAGS = $(tests_cppflags)
+tests_test_create_ipgretap_LDADD = $(tests_ldadd)
+tests_test_create_ipip_CPPFLAGS = $(tests_cppflags)
+tests_test_create_ipip_LDADD = $(tests_ldadd)
+tests_test_create_ipvlan_CPPFLAGS = $(tests_cppflags)
+tests_test_create_ipvlan_LDADD = $(tests_ldadd)
+tests_test_create_ipvti_CPPFLAGS = $(tests_cppflags)
+tests_test_create_ipvti_LDADD = $(tests_ldadd)
+tests_test_create_macsec_CPPFLAGS = $(tests_cppflags)
+tests_test_create_macsec_LDADD = $(tests_ldadd)
+tests_test_create_macvlan_CPPFLAGS = $(tests_cppflags)
+tests_test_create_macvlan_LDADD = $(tests_ldadd)
+tests_test_create_macvtap_CPPFLAGS = $(tests_cppflags)
+tests_test_create_macvtap_LDADD = $(tests_ldadd)
+tests_test_create_sit_CPPFLAGS = $(tests_cppflags)
+tests_test_create_sit_LDADD = $(tests_ldadd)
+tests_test_create_veth_CPPFLAGS = $(tests_cppflags)
+tests_test_create_veth_LDADD = $(tests_ldadd)
+tests_test_create_vlan_CPPFLAGS = $(tests_cppflags)
+tests_test_create_vlan_LDADD = $(tests_ldadd)
+tests_test_create_vrf_CPPFLAGS = $(tests_cppflags)
+tests_test_create_vrf_LDADD = $(tests_ldadd)
+tests_test_create_vxlan_CPPFLAGS = $(tests_cppflags)
+tests_test_create_vxlan_LDADD = $(tests_ldadd)
+tests_test_create_xfrmi_CPPFLAGS = $(tests_cppflags)
+tests_test_create_xfrmi_LDADD = $(tests_ldadd)
+tests_test_delete_link_CPPFLAGS = $(tests_cppflags)
+tests_test_delete_link_LDADD = $(tests_ldadd)
+tests_test_loopback_up_down_CPPFLAGS = $(tests_cppflags)
+tests_test_loopback_up_down_LDADD = $(tests_ldadd)
+tests_test_socket_creation_CPPFLAGS = $(tests_cppflags)
+tests_test_socket_creation_LDADD = $(tests_ldadd)
+tests_test_u32_filter_with_actions_CPPFLAGS = $(tests_cppflags)
+tests_test_u32_filter_with_actions_LDADD = $(tests_ldadd)
+
+check_PROGRAMS += \
+ tests/test-cache-mngr \
+ tests/test-genl \
+ tests/test-nf-cache-mngr
+
+tests_cli_ldadd = \
+ $(tests_ldadd) \
+ src/lib/libnl-cli-3.la
+
+tests_test_cache_mngr_CPPFLAGS = $(tests_cppflags)
+tests_test_cache_mngr_LDADD = $(tests_cli_ldadd)
+tests_test_genl_CPPFLAGS = $(tests_cppflags)
+tests_test_genl_LDADD = $(tests_cli_ldadd)
+tests_test_nf_cache_mngr_CPPFLAGS = $(tests_cppflags)
+tests_test_nf_cache_mngr_LDADD = $(tests_cli_ldadd)
+
+
+if WITH_CHECK
+check_programs += tests/check-all
+endif
+
+tests_check_all_SOURCES = \
+ tests/check-addr.c \
+ tests/check-all.c \
+ tests/check-attr.c \
+ tests/check-ematch-tree-clone.c \
+ tests/util.h \
+ $(NULL)
+
+tests_check_all_CPPFLAGS = \
+ $(tests_cppflags) \
+ $(CHECK_CFLAGS)
+
+tests_check_all_LDADD = \
+ $(tests_ldadd) \
+ $(CHECK_LIBS)
+
+###############################################################################
+
+dist_man8_MANS = \
+ man/genl-ctrl-list.8 \
+ man/nl-classid-lookup.8 \
+ man/nl-pktloc-lookup.8 \
+ man/nl-qdisc-add.8 \
+ man/nl-qdisc-delete.8 \
+ man/nl-qdisc-list.8 \
+ $(NULL)
+
+###############################################################################
+
+EXTRA_DIST += \
+ python/README \
+ \
+ python/doc/conf.py \
+ python/doc/core.rst \
+ python/doc/index.rst \
+ python/doc/route_addr.rst \
+ python/doc/route.rst \
+ \
+ python/examples/iface.py \
+ python/examples/nl80211.py \
+ python/examples/wiphy.py \
+ \
+ python/netlink/capi.i \
+ python/netlink/fixes.h \
+ python/netlink/__init__.py \
+ python/netlink/core.py \
+ python/netlink/util.py \
+ python/netlink/utils.h \
+ \
+ python/netlink/genl/capi.i \
+ python/netlink/genl/__init__.py \
+ \
+ python/netlink/route/capi.i \
+ python/netlink/route/__init__.py \
+ python/netlink/route/address.py \
+ python/netlink/route/link.py \
+ python/netlink/route/tc.py \
+ python/netlink/route/links/__init__.py \
+ python/netlink/route/links/dummy.py \
+ python/netlink/route/links/inet.py \
+ python/netlink/route/links/vlan.py \
+ python/netlink/route/qdisc/__init__.py \
+ python/netlink/route/qdisc/htb.py \
+ \
+ python/tests/test-create-bridge.py
+
+###############################################################################
+
+check_PROGRAMS += $(check_programs)
+TESTS += $(check_programs)
+
+if ENABLE_CLI
+pkgconfig_DATA += libnl-cli-3.0.pc
+endif
-pkgsysconfdir = ${sysconfdir}/libnl
-pkgsysconf_DATA = etc/pktloc etc/classid
+pkgsysconfdir = $(sysconfdir)/libnl
+pkgsysconf_DATA = \
+ etc/pktloc \
+ etc/classid
-EXTRA_DIST = \
- $(pkgsysconf_DATA)
+EXTRA_DIST += \
+ $(pkgsysconf_DATA) \
+ libnl-3.sym \
+ libnl-cli-3.sym \
+ libnl-genl-3.sym \
+ libnl-idiag-3.sym \
+ libnl-nf-3.sym \
+ libnl-route-3.sym \
+ libnl-xfrm-3.sym \
+ $(NULL)
diff --git a/NOTICE b/NOTICE
deleted file mode 100644
index fab48ede..00000000
--- a/NOTICE
+++ /dev/null
@@ -1,506 +0,0 @@
- GNU LESSER GENERAL PUBLIC LICENSE
- Version 2.1, February 1999
-
- Copyright (C) 1991, 1999 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
-[This is the first released version of the Lesser GPL. It also counts
- as the successor of the GNU Library Public License, version 2, hence
- the version number 2.1.]
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-Licenses are intended to guarantee your freedom to share and change
-free software--to make sure the software is free for all its users.
-
- This license, the Lesser General Public License, applies to some
-specially designated software packages--typically libraries--of the
-Free Software Foundation and other authors who decide to use it. You
-can use it too, but we suggest you first think carefully about whether
-this license or the ordinary General Public License is the better
-strategy to use in any particular case, based on the explanations below.
-
- When we speak of free software, we are referring to freedom of use,
-not price. Our General Public Licenses are designed to make sure that
-you have the freedom to distribute copies of free software (and charge
-for this service if you wish); that you receive source code or can get
-it if you want it; that you can change the software and use pieces of
-it in new free programs; and that you are informed that you can do
-these things.
-
- To protect your rights, we need to make restrictions that forbid
-distributors to deny you these rights or to ask you to surrender these
-rights. These restrictions translate to certain responsibilities for
-you if you distribute copies of the library or if you modify it.
-
- For example, if you distribute copies of the library, whether gratis
-or for a fee, you must give the recipients all the rights that we gave
-you. You must make sure that they, too, receive or can get the source
-code. If you link other code with the library, you must provide
-complete object files to the recipients, so that they can relink them
-with the library after making changes to the library and recompiling
-it. And you must show them these terms so they know their rights.
-
- We protect your rights with a two-step method: (1) we copyright the
-library, and (2) we offer you this license, which gives you legal
-permission to copy, distribute and/or modify the library.
-
- To protect each distributor, we want to make it very clear that
-there is no warranty for the free library. Also, if the library is
-modified by someone else and passed on, the recipients should know
-that what they have is not the original version, so that the original
-author's reputation will not be affected by problems that might be
-introduced by others.
-
- Finally, software patents pose a constant threat to the existence of
-any free program. We wish to make sure that a company cannot
-effectively restrict the users of a free program by obtaining a
-restrictive license from a patent holder. Therefore, we insist that
-any patent license obtained for a version of the library must be
-consistent with the full freedom of use specified in this license.
-
- Most GNU software, including some libraries, is covered by the
-ordinary GNU General Public License. This license, the GNU Lesser
-General Public License, applies to certain designated libraries, and
-is quite different from the ordinary General Public License. We use
-this license for certain libraries in order to permit linking those
-libraries into non-free programs.
-
- When a program is linked with a library, whether statically or using
-a shared library, the combination of the two is legally speaking a
-combined work, a derivative of the original library. The ordinary
-General Public License therefore permits such linking only if the
-entire combination fits its criteria of freedom. The Lesser General
-Public License permits more lax criteria for linking other code with
-the library.
-
- We call this license the "Lesser" General Public License because it
-does Less to protect the user's freedom than the ordinary General
-Public License. It also provides other free software developers Less
-of an advantage over competing non-free programs. These disadvantages
-are the reason we use the ordinary General Public License for many
-libraries. However, the Lesser license provides advantages in certain
-special circumstances.
-
- For example, on rare occasions, there may be a special need to
-encourage the widest possible use of a certain library, so that it becomes
-a de-facto standard. To achieve this, non-free programs must be
-allowed to use the library. A more frequent case is that a free
-library does the same job as widely used non-free libraries. In this
-case, there is little to gain by limiting the free library to free
-software only, so we use the Lesser General Public License.
-
- In other cases, permission to use a particular library in non-free
-programs enables a greater number of people to use a large body of
-free software. For example, permission to use the GNU C Library in
-non-free programs enables many more people to use the whole GNU
-operating system, as well as its variant, the GNU/Linux operating
-system.
-
- Although the Lesser General Public License is Less protective of the
-users' freedom, it does ensure that the user of a program that is
-linked with the Library has the freedom and the wherewithal to run
-that program using a modified version of the Library.
-
- The precise terms and conditions for copying, distribution and
-modification follow. Pay close attention to the difference between a
-"work based on the library" and a "work that uses the library". The
-former contains code derived from the library, whereas the latter must
-be combined with the library in order to run.
-
- GNU LESSER GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License Agreement applies to any software library or other
-program which contains a notice placed by the copyright holder or
-other authorized party saying it may be distributed under the terms of
-this Lesser General Public License (also called "this License").
-Each licensee is addressed as "you".
-
- A "library" means a collection of software functions and/or data
-prepared so as to be conveniently linked with application programs
-(which use some of those functions and data) to form executables.
-
- The "Library", below, refers to any such software library or work
-which has been distributed under these terms. A "work based on the
-Library" means either the Library or any derivative work under
-copyright law: that is to say, a work containing the Library or a
-portion of it, either verbatim or with modifications and/or translated
-straightforwardly into another language. (Hereinafter, translation is
-included without limitation in the term "modification".)
-
- "Source code" for a work means the preferred form of the work for
-making modifications to it. For a library, complete source code means
-all the source code for all modules it contains, plus any associated
-interface definition files, plus the scripts used to control compilation
-and installation of the library.
-
- Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running a program using the Library is not restricted, and output from
-such a program is covered only if its contents constitute a work based
-on the Library (independent of the use of the Library in a tool for
-writing it). Whether that is true depends on what the Library does
-and what the program that uses the Library does.
-
- 1. You may copy and distribute verbatim copies of the Library's
-complete source code as you receive it, in any medium, provided that
-you conspicuously and appropriately publish on each copy an
-appropriate copyright notice and disclaimer of warranty; keep intact
-all the notices that refer to this License and to the absence of any
-warranty; and distribute a copy of this License along with the
-Library.
-
- You may charge a fee for the physical act of transferring a copy,
-and you may at your option offer warranty protection in exchange for a
-fee.
-
- 2. You may modify your copy or copies of the Library or any portion
-of it, thus forming a work based on the Library, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) The modified work must itself be a software library.
-
- b) You must cause the files modified to carry prominent notices
- stating that you changed the files and the date of any change.
-
- c) You must cause the whole of the work to be licensed at no
- charge to all third parties under the terms of this License.
-
- d) If a facility in the modified Library refers to a function or a
- table of data to be supplied by an application program that uses
- the facility, other than as an argument passed when the facility
- is invoked, then you must make a good faith effort to ensure that,
- in the event an application does not supply such function or
- table, the facility still operates, and performs whatever part of
- its purpose remains meaningful.
-
- (For example, a function in a library to compute square roots has
- a purpose that is entirely well-defined independent of the
- application. Therefore, Subsection 2d requires that any
- application-supplied function or table used by this function must
- be optional: if the application does not supply it, the square
- root function must still compute square roots.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Library,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Library, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote
-it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Library.
-
-In addition, mere aggregation of another work not based on the Library
-with the Library (or with a work based on the Library) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may opt to apply the terms of the ordinary GNU General Public
-License instead of this License to a given copy of the Library. To do
-this, you must alter all the notices that refer to this License, so
-that they refer to the ordinary GNU General Public License, version 2,
-instead of to this License. (If a newer version than version 2 of the
-ordinary GNU General Public License has appeared, then you can specify
-that version instead if you wish.) Do not make any other change in
-these notices.
-
- Once this change is made in a given copy, it is irreversible for
-that copy, so the ordinary GNU General Public License applies to all
-subsequent copies and derivative works made from that copy.
-
- This option is useful when you wish to copy part of the code of
-the Library into a program that is not a library.
-
- 4. You may copy and distribute the Library (or a portion or
-derivative of it, under Section 2) in object code or executable form
-under the terms of Sections 1 and 2 above provided that you accompany
-it with the complete corresponding machine-readable source code, which
-must be distributed under the terms of Sections 1 and 2 above on a
-medium customarily used for software interchange.
-
- If distribution of object code is made by offering access to copy
-from a designated place, then offering equivalent access to copy the
-source code from the same place satisfies the requirement to
-distribute the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 5. A program that contains no derivative of any portion of the
-Library, but is designed to work with the Library by being compiled or
-linked with it, is called a "work that uses the Library". Such a
-work, in isolation, is not a derivative work of the Library, and
-therefore falls outside the scope of this License.
-
- However, linking a "work that uses the Library" with the Library
-creates an executable that is a derivative of the Library (because it
-contains portions of the Library), rather than a "work that uses the
-library". The executable is therefore covered by this License.
-Section 6 states terms for distribution of such executables.
-
- When a "work that uses the Library" uses material from a header file
-that is part of the Library, the object code for the work may be a
-derivative work of the Library even though the source code is not.
-Whether this is true is especially significant if the work can be
-linked without the Library, or if the work is itself a library. The
-threshold for this to be true is not precisely defined by law.
-
- If such an object file uses only numerical parameters, data
-structure layouts and accessors, and small macros and small inline
-functions (ten lines or less in length), then the use of the object
-file is unrestricted, regardless of whether it is legally a derivative
-work. (Executables containing this object code plus portions of the
-Library will still fall under Section 6.)
-
- Otherwise, if the work is a derivative of the Library, you may
-distribute the object code for the work under the terms of Section 6.
-Any executables containing that work also fall under Section 6,
-whether or not they are linked directly with the Library itself.
-
- 6. As an exception to the Sections above, you may also combine or
-link a "work that uses the Library" with the Library to produce a
-work containing portions of the Library, and distribute that work
-under terms of your choice, provided that the terms permit
-modification of the work for the customer's own use and reverse
-engineering for debugging such modifications.
-
- You must give prominent notice with each copy of the work that the
-Library is used in it and that the Library and its use are covered by
-this License. You must supply a copy of this License. If the work
-during execution displays copyright notices, you must include the
-copyright notice for the Library among them, as well as a reference
-directing the user to the copy of this License. Also, you must do one
-of these things:
-
- a) Accompany the work with the complete corresponding
- machine-readable source code for the Library including whatever
- changes were used in the work (which must be distributed under
- Sections 1 and 2 above); and, if the work is an executable linked
- with the Library, with the complete machine-readable "work that
- uses the Library", as object code and/or source code, so that the
- user can modify the Library and then relink to produce a modified
- executable containing the modified Library. (It is understood
- that the user who changes the contents of definitions files in the
- Library will not necessarily be able to recompile the application
- to use the modified definitions.)
-
- b) Use a suitable shared library mechanism for linking with the
- Library. A suitable mechanism is one that (1) uses at run time a
- copy of the library already present on the user's computer system,
- rather than copying library functions into the executable, and (2)
- will operate properly with a modified version of the library, if
- the user installs one, as long as the modified version is
- interface-compatible with the version that the work was made with.
-
- c) Accompany the work with a written offer, valid for at
- least three years, to give the same user the materials
- specified in Subsection 6a, above, for a charge no more
- than the cost of performing this distribution.
-
- d) If distribution of the work is made by offering access to copy
- from a designated place, offer equivalent access to copy the above
- specified materials from the same place.
-
- e) Verify that the user has already received a copy of these
- materials or that you have already sent this user a copy.
-
- For an executable, the required form of the "work that uses the
-Library" must include any data and utility programs needed for
-reproducing the executable from it. However, as a special exception,
-the materials to be distributed need not include anything that is
-normally distributed (in either source or binary form) with the major
-components (compiler, kernel, and so on) of the operating system on
-which the executable runs, unless that component itself accompanies
-the executable.
-
- It may happen that this requirement contradicts the license
-restrictions of other proprietary libraries that do not normally
-accompany the operating system. Such a contradiction means you cannot
-use both them and the Library together in an executable that you
-distribute.
-
- 7. You may place library facilities that are a work based on the
-Library side-by-side in a single library together with other library
-facilities not covered by this License, and distribute such a combined
-library, provided that the separate distribution of the work based on
-the Library and of the other library facilities is otherwise
-permitted, and provided that you do these two things:
-
- a) Accompany the combined library with a copy of the same work
- based on the Library, uncombined with any other library
- facilities. This must be distributed under the terms of the
- Sections above.
-
- b) Give prominent notice with the combined library of the fact
- that part of it is a work based on the Library, and explaining
- where to find the accompanying uncombined form of the same work.
-
- 8. You may not copy, modify, sublicense, link with, or distribute
-the Library except as expressly provided under this License. Any
-attempt otherwise to copy, modify, sublicense, link with, or
-distribute the Library is void, and will automatically terminate your
-rights under this License. However, parties who have received copies,
-or rights, from you under this License will not have their licenses
-terminated so long as such parties remain in full compliance.
-
- 9. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Library or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Library (or any work based on the
-Library), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Library or works based on it.
-
- 10. Each time you redistribute the Library (or any work based on the
-Library), the recipient automatically receives a license from the
-original licensor to copy, distribute, link with or modify the Library
-subject to these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties with
-this License.
-
- 11. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Library at all. For example, if a patent
-license would not permit royalty-free redistribution of the Library by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Library.
-
-If any portion of this section is held invalid or unenforceable under any
-particular circumstance, the balance of the section is intended to apply,
-and the section as a whole is intended to apply in other circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 12. If the distribution and/or use of the Library is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Library under this License may add
-an explicit geographical distribution limitation excluding those countries,
-so that distribution is permitted only in or among countries not thus
-excluded. In such case, this License incorporates the limitation as if
-written in the body of this License.
-
- 13. The Free Software Foundation may publish revised and/or new
-versions of the Lesser General Public License from time to time.
-Such new versions will be similar in spirit to the present version,
-but may differ in detail to address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Library
-specifies a version number of this License which applies to it and
-"any later version", you have the option of following the terms and
-conditions either of that version or of any later version published by
-the Free Software Foundation. If the Library does not specify a
-license version number, you may choose any version ever published by
-the Free Software Foundation.
-
- 14. If you wish to incorporate parts of the Library into other free
-programs whose distribution conditions are incompatible with these,
-write to the author to ask for permission. For software which is
-copyrighted by the Free Software Foundation, write to the Free
-Software Foundation; we sometimes make exceptions for this. Our
-decision will be guided by the two goals of preserving the free status
-of all derivatives of our free software and of promoting the sharing
-and reuse of software generally.
-
- NO WARRANTY
-
- 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
-WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
-EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
-OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
-KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
-IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
-LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
-THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
-WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
-AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
-FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
-CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
-LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
-RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
-FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
-SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
-DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Libraries
-
- If you develop a new library, and you want it to be of the greatest
-possible use to the public, we recommend making it free software that
-everyone can redistribute and change. You can do so by permitting
-redistribution under these terms (or, alternatively, under the terms of the
-ordinary General Public License).
-
- To apply these terms, attach the following notices to the library. It is
-safest to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least the
-"copyright" line and a pointer to where the full notice is found.
-
- <one line to give the library's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-Also add information on how to contact you by electronic and paper mail.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the library, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the
- library `Frob' (a library for tweaking knobs) written by James Random Hacker.
-
- <signature of Ty Coon>, 1 April 1990
- Ty Coon, President of Vice
-
-That's all there is to it!
-
-
-
-
diff --git a/README.version b/README.version
deleted file mode 100644
index d52ad3ad..00000000
--- a/README.version
+++ /dev/null
@@ -1,3 +0,0 @@
-URL: http://www.infradead.org/~tgr/libnl/files/libnl-2.0.tar.gz
-Version: 2.0
-BugComponent: 99150
diff --git a/configure.ac b/configure.ac
index c6f064e6..ee44d895 100644
--- a/configure.ac
+++ b/configure.ac
@@ -12,8 +12,8 @@
# copied from glib
m4_define([libnl_major_version], [3])
-m4_define([libnl_minor_version], [2])
-m4_define([libnl_micro_version], [25])
+m4_define([libnl_minor_version], [5])
+m4_define([libnl_micro_version], [0])
m4_define([libnl_git_sha], [m4_esyscmd([ ( [ -d ./.git/ ] && [ "$(readlink -f ./.git/)" = "$(readlink -f "$(git rev-parse --git-dir 2>/dev/null)" 2>/dev/null)" ] && git rev-parse --verify -q HEAD 2>/dev/null ) || true ])])
@@ -35,9 +35,9 @@ m4_define([libnl_git_sha], [m4_esyscmd([ ( [ -d ./.git/ ] && [ "$(readlink -f ./
# 3. Programs may need to be changed, recompiled, relinked in order to use
# the new version. Bump current, set revision and age to 0.
-m4_define([libnl_lt_current], [220])
-m4_define([libnl_lt_revision], [0])
-m4_define([libnl_lt_age], [20])
+m4_define([libnl_lt_current], [226])
+m4_define([libnl_lt_revision], [0])
+m4_define([libnl_lt_age], [26])
m4_define([libnl_version],
[libnl_major_version.libnl_minor_version.libnl_micro_version])
@@ -79,11 +79,10 @@ AC_C_CONST
AC_C_INLINE
PKG_CHECK_MODULES([CHECK], [check >= 0.9.0],
- [enable_unit_tests="yes"],
+ [has_check="yes"],
[AC_MSG_WARN([*** Disabling building of unit tests])
- enable_unit_tests="no"])
-
-AM_CONDITIONAL([ENABLE_UNIT_TESTS], [test "$enable_unit_tests" = "yes"])
+ has_check="no"])
+AM_CONDITIONAL(WITH_CHECK, [test "$has_check" = 'yes'])
AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=PATH],
[Path to the pkgconfig directory [[LIBDIR/pkgconfig]]]),
@@ -91,56 +90,50 @@ AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=PATH],
AC_SUBST([pkgconfigdir])
AC_ARG_ENABLE([cli],
- AS_HELP_STRING([--disable-cli], [Do not build command line interface utils]),
+ AS_HELP_STRING([--enable-cli=yes|no|no-inst|bin|sbin], [Whether to build command line interface utils. Defaults to 'yes' which is a synonym for 'bin'. 'no-inst' means only build, not installing. 'bin'/'sbin' means installing to bin/sbin directory]),
[enable_cli="$enableval"], [enable_cli="yes"])
-AM_CONDITIONAL([ENABLE_CLI], [test "$enable_cli" = "yes"])
+if test "$enable_cli" != "no" &&
+ test "$enable_cli" != "no-inst" &&
+ test "$enable_cli" != "sbin"; then
+ enable_cli="bin"
+fi
+AM_CONDITIONAL([ENABLE_CLI], [test "$enable_cli" != "no"])
+AM_CONDITIONAL([ENABLE_CLI_INSTALL_BIN], [test "$enable_cli" = "bin"])
+AM_CONDITIONAL([ENABLE_CLI_INSTALL_SBIN], [test "$enable_cli" = "sbin"])
+
+AC_CHECK_HEADERS(dlfcn.h, [], [])
AC_ARG_ENABLE([pthreads],
AS_HELP_STRING([--disable-pthreads], [Disable pthreads support]),
[enable_pthreads="$enableval"], [enable_pthreads="yes"])
AM_CONDITIONAL([DISABLE_PTHREADS], [test "$enable_pthreads" = "no"])
-
-AC_ARG_ENABLE([debug],
- AS_HELP_STRING([--disable-debug], [Do not include debugging statements]),
- [enable_debug="$enableval"], [enable_debug="yes"])
-AM_CONDITIONAL([ENABLE_DEBUG], [test "$enable_debug" = "no" ])
-
-AC_CHECK_LIB([m], [pow], [], AC_MSG_ERROR([libm is required]))
-
if test "x$enable_pthreads" = "xno"; then
AC_DEFINE([DISABLE_PTHREADS], [1], [Define to 1 to disable pthreads])
else
AC_CHECK_LIB([pthread], [pthread_mutex_lock], [], AC_MSG_ERROR([libpthread is required]))
fi
+AC_ARG_ENABLE([debug],
+ AS_HELP_STRING([--disable-debug], [Do not include debugging statements]),
+ [enable_debug="$enableval"], [enable_debug="yes"])
if test "x$enable_debug" = "xyes"; then
AC_DEFINE([NL_DEBUG], [1], [Define to 1 to enable debugging])
fi
AC_CONFIG_SUBDIRS([doc])
+AC_CHECK_FUNCS([strerror_l])
+
AC_CONFIG_FILES([
Makefile
-libnl.sym
libnl-3.0.pc
libnl-route-3.0.pc
libnl-genl-3.0.pc
libnl-nf-3.0.pc
libnl-cli-3.0.pc
-lib/Makefile
-include/Makefile
-src/Makefile
-src/lib/Makefile
-tests/Makefile
-man/Makefile
-python/Makefile
+libnl-xfrm-3.0.pc
+libnl-idiag-3.0.pc
python/setup.py
-python/doc/Makefile
-python/examples/Makefile
-python/netlink/Makefile
-python/netlink/genl/Makefile
-python/netlink/route/Makefile
-python/tests/Makefile
include/netlink/version.h
])
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index 50e8f0c9..0c4fcc42 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -1562,7 +1562,7 @@ TAGFILES =
# When a file name is specified after GENERATE_TAGFILE, doxygen will create
# a tag file that is based on the input files it reads.
-GENERATE_TAGFILE =
+GENERATE_TAGFILE = api/libnl.tag
# If the ALLEXTERNALS tag is set to YES all external classes will be listed
# in the class index. If set to NO only the inherited external classes
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 338f0772..67ae1fc9 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -2,12 +2,15 @@
.PHONY: gendoc api_ref asciidoc
-ASCIIDOCOPTS=-a pygments -a language=c -a icons \
- -a toc2 \
- -a numbered \
- -a imagesdir="./images/" \
- -a iconsdir="./images/icons" \
- -a stylesdir="${abs_srcdir}/stylesheets/"
+ASCIIDOCOPTS = \
+ -a pygments \
+ -a language=c \
+ -a icons \
+ -a toc2 \
+ -a numbered \
+ -a imagesdir="./images/" \
+ -a iconsdir="./images/icons" \
+ -a stylesdir="$(abs_srcdir)/stylesheets/"
EXTRA_DIST = \
core.txt \
@@ -38,15 +41,19 @@ if LINK_DOC
else
@echo "Warning: Linking to API reference is disabled, check configure output"
endif
-
+
%.html: %.txt link_doc
+if HAVE_ASCIIDOC
./resolve-asciidoc-refs.py $< > asciidoc.tmp
asciidoc $(ASCIIDOCOPTS) -o $@ asciidoc.tmp
if LINK_DOC
./doxygen-link.py libnl.dict $@ > asciidoc.tmp
mv asciidoc.tmp $@
endif
+else
+ @echo "Warning: Building of asciidoc files is disabled, check autoconf logs"
+endif
asciidoc: core.html route.html index.html
@@ -70,4 +77,4 @@ else
endif
clean-local:
- rm -f api/* libnl.dict *.html;
+ rm -f api/* libnl.dict *.html
diff --git a/doc/api/.gitignore b/doc/api/.gitignore
index e57ca889..cdef49d7 100644
--- a/doc/api/.gitignore
+++ b/doc/api/.gitignore
@@ -4,5 +4,6 @@
*.map
*.md5
*.js
+*.tag
formula.repository
jquery.js
diff --git a/doc/configure.ac b/doc/configure.ac
index d4cda857..187447c9 100644
--- a/doc/configure.ac
+++ b/doc/configure.ac
@@ -9,14 +9,12 @@
# Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
#
-AC_INIT(libnl-doc, [3.2.25], [http://www.infradead.org/~tgr/libnl/])
+AC_INIT(libnl-doc, [3.5.0], [http://www.infradead.org/~tgr/libnl/])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([foreign])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES(yes)], [])
-m4_include([m4/ax_python.m4])
-
#
# Generating the documentation
#
@@ -24,12 +22,15 @@ AC_ARG_ENABLE([doc],
AS_HELP_STRING([--disable-doc], [Do not generate documentation]),
[generate_doc="$enableval"], [generate_doc=auto])
-AX_PYTHON
-
if test "x$generate_doc" != "xno"; then
AC_PROG_SED
AC_PROG_EGREP
+ AC_CHECK_PROG(HAVE_PYTHON, [python], yes, no)
+ if test "x$HAVE_PYTHON" = "xno" -a "x$generate_doc" = "xyes"; then
+ AC_MSG_ERROR([*** python binary required to generate documentation])
+ fi
+
AC_CHECK_PROG(HAVE_DOXYGEN, [doxygen], yes, no)
if test "x$HAVE_DOXYGEN" = "xno" -a "x$generate_doc" = "xyes"; then
AC_MSG_ERROR([*** doxygen package required to generate documentation])
diff --git a/doc/m4/ax_python.m4 b/doc/m4/ax_python.m4
deleted file mode 100644
index f9a51359..00000000
--- a/doc/m4/ax_python.m4
+++ /dev/null
@@ -1,97 +0,0 @@
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_python.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_PYTHON
-#
-# DESCRIPTION
-#
-# This macro does a complete Python development environment check.
-#
-# It recurses through several python versions (from 2.1 to 2.6 in this
-# version), looking for an executable. When it finds an executable, it
-# looks to find the header files and library.
-#
-# It sets PYTHON_BIN to the name of the python executable,
-# PYTHON_INCLUDE_DIR to the directory holding the header files, and
-# PYTHON_LIB to the name of the Python library.
-#
-# This macro calls AC_SUBST on PYTHON_BIN (via AC_CHECK_PROG),
-# PYTHON_INCLUDE_DIR and PYTHON_LIB.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Michael Tindal
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 2 of the License, or (at your
-# option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 9
-
-AC_DEFUN([AX_PYTHON],
-[AC_MSG_CHECKING(for python build information)
-AC_MSG_RESULT([])
-for python in python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python; do
-AC_CHECK_PROGS(PYTHON_BIN, [$python])
-ax_python_bin=$PYTHON_BIN
-if test x$ax_python_bin != x; then
- AC_CHECK_LIB($ax_python_bin, main, ax_python_lib=$ax_python_bin, ax_python_lib=no)
- AC_CHECK_HEADER([$ax_python_bin/Python.h],
- [[ax_python_header=`locate $ax_python_bin/Python.h | sed -e s,/Python.h,,`]],
- ax_python_header=no)
- if test x$ax_python_lib != xno; then
- if test x$ax_python_header != xno; then
- break;
- fi
- fi
-fi
-done
-if test x$ax_python_bin = x; then
- ax_python_bin=no
-fi
-if test x$ax_python_header = x; then
- ax_python_header=no
-fi
-if test x$ax_python_lib = x; then
- ax_python_lib=no
-fi
-
-AC_MSG_RESULT([ results of the Python check:])
-AC_MSG_RESULT([ Binary: $ax_python_bin])
-AC_MSG_RESULT([ Library: $ax_python_lib])
-AC_MSG_RESULT([ Include Dir: $ax_python_header])
-
-if test x$ax_python_header != xno; then
- PYTHON_INCLUDE_DIR=$ax_python_header
- AC_SUBST(PYTHON_INCLUDE_DIR)
-fi
-if test x$ax_python_lib != xno; then
- PYTHON_LIB=$ax_python_lib
- AC_SUBST(PYTHON_LIB)
-fi
-])dnl
diff --git a/doc/route.txt b/doc/route.txt
index d9f88e13..9d4c23aa 100644
--- a/doc/route.txt
+++ b/doc/route.txt
@@ -763,6 +763,63 @@ if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0)
rtnl_link_put(link);
-----
+[[link_macvtap]]
+==== MACVTAP
+
+[source,c]
+-----
+extern struct rtnl_link *rtnl_link_macvtap_alloc(void);
+
+extern int rtnl_link_is_macvtap(struct rtnl_link *);
+
+extern char * rtnl_link_macvtap_mode2str(int, char *, size_t);
+extern int rtnl_link_macvtap_str2mode(const char *);
+
+extern char * rtnl_link_macvtap_flags2str(int, char *, size_t);
+extern int rtnl_link_macvtap_str2flags(const char *);
+
+extern int rtnl_link_macvtap_set_mode(struct rtnl_link *,
+ uint32_t);
+extern uint32_t rtnl_link_macvtap_get_mode(struct rtnl_link *);
+
+extern int rtnl_link_macvtap_set_flags(struct rtnl_link *,
+ uint16_t);
+extern int rtnl_link_macvtap_unset_flags(struct rtnl_link *,
+ uint16_t);
+extern uint16_t rtnl_link_macvtap_get_flags(struct rtnl_link *);
+-----
+
+.Example: Add a MACVTAP device
+[source,c]
+-----
+struct rtnl_link *link;
+int master_index;
+struct nl_addr* addr;
+
+/* lookup interface index of eth0 */
+if (!(master_index = rtnl_link_name2i(link_cache, "eth0")))
+ /* error */
+
+/* allocate new link object of type macvtap */
+link = rtnl_link_macvtap_alloc();
+
+/* set eth0 to be our master device */
+rtnl_link_set_link(link, master_index);
+
+/* set address of virtual interface */
+addr = nl_addr_build(AF_LLC, ether_aton("00:11:22:33:44:55"), ETH_ALEN);
+rtnl_link_set_addr(link, addr);
+nl_addr_put(addr);
+
+/* set mode of virtual interface */
+rtnl_link_macvtap_set_mode(link, rtnl_link_macvtap_str2mode("bridge"));
+
+if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0)
+ /* error */
+
+rtnl_link_put(link);
+-----
+
[[link_vxlan]]
==== VXLAN
@@ -892,7 +949,7 @@ extern uint8_t rtnl_link_ipip_get_pmtudisc(struct rtnl_link *link);
struct rtnl_link *link
struct in_addr addr
-/* allocate new link object of type vxlan */
+/* allocate new link object of type ipip */
if(!(link = rtnl_link_ipip_alloc()))
/* error */
@@ -970,7 +1027,7 @@ extern uint8_t rtnl_link_ipgre_get_pmtudisc(struct rtnl_link *link);
struct rtnl_link *link
struct in_addr addr
-/* allocate new link object of type vxlan */
+/* allocate new link object of type ipgre */
if(!(link = rtnl_link_ipgre_alloc()))
/* error */
@@ -1048,7 +1105,7 @@ extern uint8_t rtnl_link_sit_get_pmtudisc(struct rtnl_link *link);
struct rtnl_link *link
struct in_addr addr
-/* allocate new link object of type vxlan */
+/* allocate new link object of type sit */
if(!(link = rtnl_link_sit_alloc()))
/* error */
@@ -1093,10 +1150,10 @@ extern int rtnl_link_ipvti_set_link(struct rtnl_link *link, uint32_t index);
extern uint32_t rtnl_link_ipvti_get_link(struct rtnl_link *link);
extern int rtnl_link_ipvti_set_ikey(struct rtnl_link *link, uint32_t ikey);
-extern uint32_t rtnl_link_get_ikey(struct rtnl_link *link);
+extern uint32_t rtnl_link_ipvti_get_ikey(struct rtnl_link *link);
extern int rtnl_link_ipvti_set_okey(struct rtnl_link *link, uint32_t okey);
-extern uint32_t rtnl_link_get_okey(struct rtnl_link *link)
+extern uint32_t rtnl_link_ipvti_get_okey(struct rtnl_link *link)
extern int rtnl_link_ipvti_set_local(struct rtnl_link *link, uint32_t addr);
extern uint32_t rtnl_link_ipvti_get_local(struct rtnl_link *link);
@@ -1112,7 +1169,7 @@ extern uint32_t rtnl_link_ipvti_get_remote(struct rtnl_link *link);
struct rtnl_link *link
struct in_addr addr
-/* allocate new link object of type vxlan */
+/* allocate new link object of type ipvti */
if(!(link = rtnl_link_ipvti_alloc()))
/* error */
@@ -1200,6 +1257,49 @@ rtnl_link_put(link);
-----
+[[link_xfrmi]]
+==== XFRMI
+
+[source,c]
+-----
+extern struct rtnl_link *rtnl_link_xfrmi_alloc(void);
+
+extern int rtnl_link_xfrmi_set_link(struct rtnl_link *link, uint32_t index);
+extern uint32_t rtnl_link_xfrmi_get_link(struct rtnl_link *link);
+
+extern int rtnl_link_xfrmi_set_if_id(struct rtnl_link *link, uint32_t if_id);
+extern uint32_t rtnl_link_xfrmi_get_if_id(struct rtnl_link *link);
+
+-----
+
+.Example: Add a xfrmi device
+[source,c]
+-----
+struct rtnl_link *link
+struct in_addr addr
+
+/* allocate new link object of type xfrmi */
+if(!(link = rtnl_link_xfrmi_alloc()))
+ /* error */
+
+/* set xfrmi name */
+if ((err = rtnl_link_set_name(link, "ipsec0")) < 0)
+ /* error */
+
+/* set link index */
+if ((err = rtnl_link_xfrmi_set_link(link, if_index)) < 0)
+ /* error */
+
+/* set if_id */
+if ((err = rtnl_link_xfrmi_set_if_id(link, 16)) < 0)
+ /* error */
+
+if((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0)
+ /* error */
+
+rtnl_link_put(link);
+-----
+
== Neighbouring
== Routing
diff --git a/doc/src/toc.c b/doc/src/toc.c
index a91c2a71..921bcf6c 100644
--- a/doc/src/toc.c
+++ b/doc/src/toc.c
@@ -17,7 +17,7 @@ libraries (e.g. "nl-route", "nl-genl", ...).
The library is designed to ensure that all components are optional, i.e.
even though the core library provides a caching system which allows to
-easly manage objects of any kind, no application is required to use this
+easily manage objects of any kind, no application is required to use this
caching system if it has no need for it.
The library was developed and tested on 2.6.x and 3.x kernel releases. It
@@ -39,7 +39,7 @@ git://git.infradead.org/users/tgr/libnl.git
\section main_website Website
-- http://www.infradead.org/~tgr/libnl/
+- https://www.infradead.org/~tgr/libnl/
\section main_mailinglist Mailinglist
@@ -49,6 +49,6 @@ Please post questions and patches to the libnl mailinglist:
libnl@lists.infradead.org
@endcode
-- Archives: http://canuck.infradead.org/pipermail/libnl/
+- Archives: https://lists.infradead.org/pipermail/libnl/
*/
diff --git a/etc/pktloc b/etc/pktloc
index 505c44e6..8559161b 100644
--- a/etc/pktloc
+++ b/etc/pktloc
@@ -58,7 +58,7 @@ tcp.flag.urg u8 tcp+13 0x20 5
tcp.flag.ack u8 tcp+13 0x10 4
tcp.flag.psh u8 tcp+13 0x08 3
tcp.flag.rst u8 tcp+13 0x04 2
-tpc.flag.syn u8 tcp+13 0x02 1
+tcp.flag.syn u8 tcp+13 0x02 1
tcp.flag.fin u8 tcp+13 0x01
tcp.win u16 tcp+14
diff --git a/include/Makefile.am b/include/Makefile.am
deleted file mode 100644
index 765cf5a9..00000000
--- a/include/Makefile.am
+++ /dev/null
@@ -1,153 +0,0 @@
-# -*- Makefile -*-
-
-libnlincludedir = $(includedir)/libnl@MAJ_VERSION@
-
-nobase_libnlinclude_HEADERS = \
- netlink/fib_lookup/lookup.h \
- netlink/fib_lookup/request.h \
- netlink/genl/ctrl.h \
- netlink/genl/family.h \
- netlink/genl/genl.h \
- netlink/genl/mngt.h \
- netlink/netfilter/ct.h \
- netlink/netfilter/exp.h \
- netlink/netfilter/log.h \
- netlink/netfilter/log_msg.h \
- netlink/netfilter/netfilter.h \
- netlink/netfilter/nfnl.h \
- netlink/netfilter/queue.h \
- netlink/netfilter/queue_msg.h \
- netlink/addr.h \
- netlink/attr.h \
- netlink/cache.h \
- netlink/data.h \
- netlink/errno.h \
- netlink/handlers.h \
- netlink/hash.h \
- netlink/hashtable.h \
- netlink/list.h \
- netlink/msg.h \
- netlink/netlink-compat.h \
- netlink/netlink-kernel.h \
- netlink/netlink.h \
- netlink/object.h \
- netlink/route/action.h \
- netlink/route/act/mirred.h \
- netlink/route/cls/ematch/cmp.h \
- netlink/route/cls/ematch/meta.h \
- netlink/route/cls/ematch/nbyte.h \
- netlink/route/cls/ematch/text.h \
- netlink/route/cls/basic.h \
- netlink/route/cls/cgroup.h \
- netlink/route/cls/ematch.h \
- netlink/route/cls/fw.h \
- netlink/route/cls/police.h \
- netlink/route/cls/u32.h \
- netlink/route/link/api.h \
- netlink/route/link/bonding.h \
- netlink/route/link/bridge.h \
- netlink/route/link/can.h \
- netlink/route/link/inet.h \
- netlink/route/link/info-api.h \
- netlink/route/link/macvlan.h \
- netlink/route/link/vlan.h \
- netlink/route/link/vxlan.h \
- netlink/route/link/veth.h \
- netlink/route/link/ip6tnl.h \
- netlink/route/link/ipgre.h \
- netlink/route/link/ipip.h \
- netlink/route/link/ipvti.h \
- netlink/route/link/sit.h \
- netlink/route/qdisc/cbq.h \
- netlink/route/qdisc/dsmark.h \
- netlink/route/qdisc/fifo.h \
- netlink/route/qdisc/htb.h \
- netlink/route/qdisc/netem.h \
- netlink/route/qdisc/prio.h \
- netlink/route/qdisc/red.h \
- netlink/route/qdisc/sfq.h \
- netlink/route/qdisc/tbf.h \
- netlink/route/qdisc/plug.h \
- netlink/route/qdisc/fq_codel.h \
- netlink/route/addr.h \
- netlink/route/class.h \
- netlink/route/classifier.h \
- netlink/route/link.h \
- netlink/route/neighbour.h \
- netlink/route/neightbl.h \
- netlink/route/nexthop.h \
- netlink/route/pktloc.h \
- netlink/route/qdisc.h \
- netlink/route/route.h \
- netlink/route/rtnl.h \
- netlink/route/rule.h \
- netlink/route/tc.h \
- netlink/socket.h \
- netlink/types.h \
- netlink/utils.h \
- netlink/version.h \
- netlink/cache-api.h \
- netlink/object-api.h \
- netlink/route/tc-api.h \
- netlink/idiag/idiagnl.h \
- netlink/idiag/meminfo.h \
- netlink/idiag/msg.h \
- netlink/idiag/req.h \
- netlink/idiag/vegasinfo.h
-
-if ENABLE_CLI
-nobase_libnlinclude_HEADERS += \
- netlink/cli/addr.h \
- netlink/cli/class.h \
- netlink/cli/cls.h \
- netlink/cli/ct.h \
- netlink/cli/exp.h \
- netlink/cli/link.h \
- netlink/cli/neigh.h \
- netlink/cli/qdisc.h \
- netlink/cli/route.h \
- netlink/cli/rule.h \
- netlink/cli/tc.h \
- netlink/cli/utils.h
-endif
-
-noinst_HEADERS = \
- linux/fib_rules.h \
- linux/genetlink.h \
- linux/gen_stats.h \
- linux/if_addr.h \
- linux/if_arp.h \
- linux/if_ether.h \
- linux/if.h \
- linux/if_bridge.h \
- linux/if_link.h \
- linux/if_tunnel.h \
- linux/if_vlan.h \
- linux/ip.h \
- linux/ip_mp_alg.h \
- linux/ipv6.h \
- linux/can/netlink.h \
- linux/neighbour.h \
- linux/netfilter.h \
- linux/netfilter/nf_conntrack_common.h \
- linux/netfilter/nfnetlink_compat.h \
- linux/netfilter/nfnetlink_conntrack.h \
- linux/netfilter/nfnetlink.h \
- linux/netfilter/nfnetlink_log.h \
- linux/netfilter/nfnetlink_queue.h \
- linux/netlink.h \
- linux/pkt_cls.h \
- linux/tc_act/tc_mirred.h \
- linux/pkt_sched.h \
- linux/rtnetlink.h \
- linux/snmp.h \
- linux/tc_ematch/tc_em_meta.h \
- netlink-private/genl.h \
- netlink-private/netlink.h \
- netlink-private/socket.h \
- netlink-private/tc.h \
- netlink-private/types.h \
- netlink-private/cache-api.h \
- netlink-private/object-api.h \
- netlink-private/route/link/api.h \
- netlink-private/route/tc-api.h
diff --git a/include/linux-private/linux/can/netlink.h b/include/linux-private/linux/can/netlink.h
index 14966ddb..f0c5e58b 100644
--- a/include/linux-private/linux/can/netlink.h
+++ b/include/linux-private/linux/can/netlink.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* linux/can/netlink.h
*
@@ -5,10 +6,18 @@
*
* Copyright (c) 2009 Wolfgang Grandegger <wg@grandegger.com>
*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*/
-#ifndef CAN_NETLINK_H
-#define CAN_NETLINK_H
+#ifndef _CAN_NETLINK_H
+#define _CAN_NETLINK_H
#include <linux/types.h>
@@ -84,10 +93,13 @@ struct can_ctrlmode {
};
#define CAN_CTRLMODE_LOOPBACK 0x01 /* Loopback mode */
-#define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */
+#define CAN_CTRLMODE_LISTENONLY 0x02 /* Listen-only mode */
#define CAN_CTRLMODE_3_SAMPLES 0x04 /* Triple sampling mode */
#define CAN_CTRLMODE_ONE_SHOT 0x08 /* One-Shot mode */
#define CAN_CTRLMODE_BERR_REPORTING 0x10 /* Bus-error reporting */
+#define CAN_CTRLMODE_FD 0x20 /* CAN FD mode */
+#define CAN_CTRLMODE_PRESUME_ACK 0x40 /* Ignore missing CAN ACKs */
+#define CAN_CTRLMODE_FD_NON_ISO 0x80 /* CAN FD in non-ISO mode */
/*
* CAN device statistics
@@ -114,9 +126,19 @@ enum {
IFLA_CAN_RESTART_MS,
IFLA_CAN_RESTART,
IFLA_CAN_BERR_COUNTER,
+ IFLA_CAN_DATA_BITTIMING,
+ IFLA_CAN_DATA_BITTIMING_CONST,
+ IFLA_CAN_TERMINATION,
+ IFLA_CAN_TERMINATION_CONST,
+ IFLA_CAN_BITRATE_CONST,
+ IFLA_CAN_DATA_BITRATE_CONST,
+ IFLA_CAN_BITRATE_MAX,
__IFLA_CAN_MAX
};
#define IFLA_CAN_MAX (__IFLA_CAN_MAX - 1)
-#endif /* CAN_NETLINK_H */
+/* u16 termination range: 1..65535 Ohms */
+#define CAN_TERMINATION_DISABLED 0
+
+#endif /* !_UAPI_CAN_NETLINK_H */
diff --git a/include/linux-private/linux/fib_rules.h b/include/linux-private/linux/fib_rules.h
index ed4504a8..232df14e 100644
--- a/include/linux-private/linux/fib_rules.h
+++ b/include/linux-private/linux/fib_rules.h
@@ -1,6 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_FIB_RULES_H
#define __LINUX_FIB_RULES_H
+#include <linux/types.h>
+#include <linux/rtnetlink.h>
+
/* rule is permanent, and cannot be deleted */
#define FIB_RULE_PERMANENT 0x00000001
#define FIB_RULE_INVERT 0x00000002
@@ -19,13 +23,23 @@ struct fib_rule_hdr {
__u8 tos;
__u8 table;
- __u8 res1; /* reserved */
+ __u8 res1; /* reserved */
__u8 res2; /* reserved */
__u8 action;
__u32 flags;
};
+struct fib_rule_uid_range {
+ __u32 start;
+ __u32 end;
+};
+
+struct fib_rule_port_range {
+ __u16 start;
+ __u16 end;
+};
+
enum {
FRA_UNSPEC,
FRA_DST, /* destination address */
@@ -40,12 +54,19 @@ enum {
FRA_UNUSED5,
FRA_FWMARK, /* mark */
FRA_FLOW, /* flow/class id */
- FRA_UNUSED6,
- FRA_UNUSED7,
- FRA_UNUSED8,
+ FRA_TUN_ID,
+ FRA_SUPPRESS_IFGROUP,
+ FRA_SUPPRESS_PREFIXLEN,
FRA_TABLE, /* Extended table id */
FRA_FWMASK, /* mask for netfilter mark */
FRA_OIFNAME,
+ FRA_PAD,
+ FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
+ FRA_UID_RANGE, /* UID range */
+ FRA_PROTOCOL, /* Originator of the rule */
+ FRA_IP_PROTO, /* ip proto */
+ FRA_SPORT_RANGE, /* sport */
+ FRA_DPORT_RANGE, /* dport */
__FRA_MAX
};
diff --git a/include/linux-private/linux/gen_stats.h b/include/linux-private/linux/gen_stats.h
index 552c8a0a..24a861c0 100644
--- a/include/linux-private/linux/gen_stats.h
+++ b/include/linux-private/linux/gen_stats.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_GEN_STATS_H
#define __LINUX_GEN_STATS_H
@@ -9,6 +10,8 @@ enum {
TCA_STATS_RATE_EST,
TCA_STATS_QUEUE,
TCA_STATS_APP,
+ TCA_STATS_RATE_EST64,
+ TCA_STATS_PAD,
__TCA_STATS_MAX,
};
#define TCA_STATS_MAX (__TCA_STATS_MAX - 1)
@@ -38,6 +41,16 @@ struct gnet_stats_rate_est {
};
/**
+ * struct gnet_stats_rate_est64 - rate estimator
+ * @bps: current byte rate
+ * @pps: current packet rate
+ */
+struct gnet_stats_rate_est64 {
+ __u64 bps;
+ __u64 pps;
+};
+
+/**
* struct gnet_stats_queue - queuing statistics
* @qlen: queue length
* @backlog: backlog size of queue
diff --git a/include/linux-private/linux/genetlink.h b/include/linux-private/linux/genetlink.h
index b834ef6d..1317119c 100644
--- a/include/linux-private/linux/genetlink.h
+++ b/include/linux-private/linux/genetlink.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_GENERIC_NETLINK_H
#define __LINUX_GENERIC_NETLINK_H
@@ -21,12 +22,16 @@ struct genlmsghdr {
#define GENL_CMD_CAP_DO 0x02
#define GENL_CMD_CAP_DUMP 0x04
#define GENL_CMD_CAP_HASPOL 0x08
+#define GENL_UNS_ADMIN_PERM 0x10
/*
* List of reserved static generic netlink identifiers:
*/
-#define GENL_ID_GENERATE 0
#define GENL_ID_CTRL NLMSG_MIN_TYPE
+#define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1)
+#define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2)
+/* must be last reserved + 1 */
+#define GENL_START_ALLOC (NLMSG_MIN_TYPE + 3)
/**************************************************************************
* Controller
@@ -80,4 +85,5 @@ enum {
#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1)
-#endif /* __LINUX_GENERIC_NETLINK_H */
+
+#endif /* __LINUX_GENERIC_NETLINK_H */
diff --git a/include/linux-private/linux/if.h b/include/linux-private/linux/if.h
new file mode 100644
index 00000000..495cdd23
--- /dev/null
+++ b/include/linux-private/linux/if.h
@@ -0,0 +1,293 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the INET interface module.
+ *
+ * Version: @(#)if.h 1.0.2 04/18/93
+ *
+ * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988
+ * Ross Biro
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_H
+#define _LINUX_IF_H
+
+#include <linux/libc-compat.h> /* for compatibility with glibc */
+#include <linux/types.h> /* for "__kernel_caddr_t" et al */
+#include <linux/socket.h> /* for "struct sockaddr" et al */
+ /* for "__user" et al */
+
+#include <sys/socket.h> /* for struct sockaddr. */
+
+#if __UAPI_DEF_IF_IFNAMSIZ
+#define IFNAMSIZ 16
+#endif /* __UAPI_DEF_IF_IFNAMSIZ */
+#define IFALIASZ 256
+#include <linux/hdlc/ioctl.h>
+
+/* For glibc compatibility. An empty enum does not compile. */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || \
+ __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0
+/**
+ * enum net_device_flags - &struct net_device flags
+ *
+ * These are the &struct net_device flags, they can be set by drivers, the
+ * kernel and some can be triggered by userspace. Userspace can query and
+ * set these flags using userspace utilities but there is also a sysfs
+ * entry available for all dev flags which can be queried and set. These flags
+ * are shared for all types of net_devices. The sysfs entries are available
+ * via /sys/class/net/<dev>/flags. Flags which can be toggled through sysfs
+ * are annotated below, note that only a few flags can be toggled and some
+ * other flags are always preserved from the original net_device flags
+ * even if you try to set them via sysfs. Flags which are always preserved
+ * are kept under the flag grouping @IFF_VOLATILE. Flags which are __volatile__
+ * are annotated below as such.
+ *
+ * You should have a pretty good reason to be extending these flags.
+ *
+ * @IFF_UP: interface is up. Can be toggled through sysfs.
+ * @IFF_BROADCAST: broadcast address valid. Volatile.
+ * @IFF_DEBUG: turn on debugging. Can be toggled through sysfs.
+ * @IFF_LOOPBACK: is a loopback net. Volatile.
+ * @IFF_POINTOPOINT: interface is has p-p link. Volatile.
+ * @IFF_NOTRAILERS: avoid use of trailers. Can be toggled through sysfs.
+ * Volatile.
+ * @IFF_RUNNING: interface RFC2863 OPER_UP. Volatile.
+ * @IFF_NOARP: no ARP protocol. Can be toggled through sysfs. Volatile.
+ * @IFF_PROMISC: receive all packets. Can be toggled through sysfs.
+ * @IFF_ALLMULTI: receive all multicast packets. Can be toggled through
+ * sysfs.
+ * @IFF_MASTER: master of a load balancer. Volatile.
+ * @IFF_SLAVE: slave of a load balancer. Volatile.
+ * @IFF_MULTICAST: Supports multicast. Can be toggled through sysfs.
+ * @IFF_PORTSEL: can set media type. Can be toggled through sysfs.
+ * @IFF_AUTOMEDIA: auto media select active. Can be toggled through sysfs.
+ * @IFF_DYNAMIC: dialup device with changing addresses. Can be toggled
+ * through sysfs.
+ * @IFF_LOWER_UP: driver signals L1 up. Volatile.
+ * @IFF_DORMANT: driver signals dormant. Volatile.
+ * @IFF_ECHO: echo sent packets. Volatile.
+ */
+enum net_device_flags {
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS
+ IFF_UP = 1<<0, /* sysfs */
+ IFF_BROADCAST = 1<<1, /* __volatile__ */
+ IFF_DEBUG = 1<<2, /* sysfs */
+ IFF_LOOPBACK = 1<<3, /* __volatile__ */
+ IFF_POINTOPOINT = 1<<4, /* __volatile__ */
+ IFF_NOTRAILERS = 1<<5, /* sysfs */
+ IFF_RUNNING = 1<<6, /* __volatile__ */
+ IFF_NOARP = 1<<7, /* sysfs */
+ IFF_PROMISC = 1<<8, /* sysfs */
+ IFF_ALLMULTI = 1<<9, /* sysfs */
+ IFF_MASTER = 1<<10, /* __volatile__ */
+ IFF_SLAVE = 1<<11, /* __volatile__ */
+ IFF_MULTICAST = 1<<12, /* sysfs */
+ IFF_PORTSEL = 1<<13, /* sysfs */
+ IFF_AUTOMEDIA = 1<<14, /* sysfs */
+ IFF_DYNAMIC = 1<<15, /* sysfs */
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
+ IFF_LOWER_UP = 1<<16, /* __volatile__ */
+ IFF_DORMANT = 1<<17, /* __volatile__ */
+ IFF_ECHO = 1<<18, /* __volatile__ */
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
+};
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */
+
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS
+#define IFF_UP IFF_UP
+#define IFF_BROADCAST IFF_BROADCAST
+#define IFF_DEBUG IFF_DEBUG
+#define IFF_LOOPBACK IFF_LOOPBACK
+#define IFF_POINTOPOINT IFF_POINTOPOINT
+#define IFF_NOTRAILERS IFF_NOTRAILERS
+#define IFF_RUNNING IFF_RUNNING
+#define IFF_NOARP IFF_NOARP
+#define IFF_PROMISC IFF_PROMISC
+#define IFF_ALLMULTI IFF_ALLMULTI
+#define IFF_MASTER IFF_MASTER
+#define IFF_SLAVE IFF_SLAVE
+#define IFF_MULTICAST IFF_MULTICAST
+#define IFF_PORTSEL IFF_PORTSEL
+#define IFF_AUTOMEDIA IFF_AUTOMEDIA
+#define IFF_DYNAMIC IFF_DYNAMIC
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */
+
+#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
+#define IFF_LOWER_UP IFF_LOWER_UP
+#define IFF_DORMANT IFF_DORMANT
+#define IFF_ECHO IFF_ECHO
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
+
+#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
+ IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
+
+#define IF_GET_IFACE 0x0001 /* for querying only */
+#define IF_GET_PROTO 0x0002
+
+/* For definitions see hdlc.h */
+#define IF_IFACE_V35 0x1000 /* V.35 serial interface */
+#define IF_IFACE_V24 0x1001 /* V.24 serial interface */
+#define IF_IFACE_X21 0x1002 /* X.21 serial interface */
+#define IF_IFACE_T1 0x1003 /* T1 telco serial interface */
+#define IF_IFACE_E1 0x1004 /* E1 telco serial interface */
+#define IF_IFACE_SYNC_SERIAL 0x1005 /* can't be set by software */
+#define IF_IFACE_X21D 0x1006 /* X.21 Dual Clocking (FarSite) */
+
+/* For definitions see hdlc.h */
+#define IF_PROTO_HDLC 0x2000 /* raw HDLC protocol */
+#define IF_PROTO_PPP 0x2001 /* PPP protocol */
+#define IF_PROTO_CISCO 0x2002 /* Cisco HDLC protocol */
+#define IF_PROTO_FR 0x2003 /* Frame Relay protocol */
+#define IF_PROTO_FR_ADD_PVC 0x2004 /* Create FR PVC */
+#define IF_PROTO_FR_DEL_PVC 0x2005 /* Delete FR PVC */
+#define IF_PROTO_X25 0x2006 /* X.25 */
+#define IF_PROTO_HDLC_ETH 0x2007 /* raw HDLC, Ethernet emulation */
+#define IF_PROTO_FR_ADD_ETH_PVC 0x2008 /* Create FR Ethernet-bridged PVC */
+#define IF_PROTO_FR_DEL_ETH_PVC 0x2009 /* Delete FR Ethernet-bridged PVC */
+#define IF_PROTO_FR_PVC 0x200A /* for reading PVC status */
+#define IF_PROTO_FR_ETH_PVC 0x200B
+#define IF_PROTO_RAW 0x200C /* RAW Socket */
+
+/* RFC 2863 operational status */
+enum {
+ IF_OPER_UNKNOWN,
+ IF_OPER_NOTPRESENT,
+ IF_OPER_DOWN,
+ IF_OPER_LOWERLAYERDOWN,
+ IF_OPER_TESTING,
+ IF_OPER_DORMANT,
+ IF_OPER_UP,
+};
+
+/* link modes */
+enum {
+ IF_LINK_MODE_DEFAULT,
+ IF_LINK_MODE_DORMANT, /* limit upward transition to dormant */
+};
+
+/*
+ * Device mapping structure. I'd just gone off and designed a
+ * beautiful scheme using only loadable modules with arguments
+ * for driver options and along come the PCMCIA people 8)
+ *
+ * Ah well. The get() side of this is good for WDSETUP, and it'll
+ * be handy for debugging things. The set side is fine for now and
+ * being very small might be worth keeping for clean configuration.
+ */
+
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFMAP
+struct ifmap {
+ unsigned long mem_start;
+ unsigned long mem_end;
+ unsigned short base_addr;
+ unsigned char irq;
+ unsigned char dma;
+ unsigned char port;
+ /* 3 bytes spare */
+};
+#endif /* __UAPI_DEF_IF_IFMAP */
+
+struct if_settings {
+ unsigned int type; /* Type of physical device or protocol */
+ unsigned int size; /* Size of the data allocated by the caller */
+ union {
+ /* {atm/eth/dsl}_settings anyone ? */
+ raw_hdlc_proto *raw_hdlc;
+ cisco_proto *cisco;
+ fr_proto *fr;
+ fr_proto_pvc *fr_pvc;
+ fr_proto_pvc_info *fr_pvc_info;
+
+ /* interface settings */
+ sync_serial_settings *sync;
+ te1_settings *te1;
+ } ifs_ifsu;
+};
+
+/*
+ * Interface request structure used for socket
+ * ioctl's. All interface ioctl's must have parameter
+ * definitions which begin with ifr_name. The
+ * remainder may be interface specific.
+ */
+
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFREQ
+struct ifreq {
+#define IFHWADDRLEN 6
+ union
+ {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ } ifr_ifrn;
+
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_dstaddr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr ifru_netmask;
+ struct sockaddr ifru_hwaddr;
+ short ifru_flags;
+ int ifru_ivalue;
+ int ifru_mtu;
+ struct ifmap ifru_map;
+ char ifru_slave[IFNAMSIZ]; /* Just fits the size */
+ char ifru_newname[IFNAMSIZ];
+ void * ifru_data;
+ struct if_settings ifru_settings;
+ } ifr_ifru;
+};
+#endif /* __UAPI_DEF_IF_IFREQ */
+
+#define ifr_name ifr_ifrn.ifrn_name /* interface name */
+#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
+#define ifr_addr ifr_ifru.ifru_addr /* address */
+#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
+#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
+#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
+#define ifr_flags ifr_ifru.ifru_flags /* flags */
+#define ifr_metric ifr_ifru.ifru_ivalue /* metric */
+#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
+#define ifr_map ifr_ifru.ifru_map /* device map */
+#define ifr_slave ifr_ifru.ifru_slave /* slave device */
+#define ifr_data ifr_ifru.ifru_data /* for use by interface */
+#define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */
+#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
+#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */
+#define ifr_newname ifr_ifru.ifru_newname /* New name */
+#define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/
+
+/*
+ * Structure used in SIOCGIFCONF request.
+ * Used to retrieve interface configuration
+ * for machine (useful for programs which
+ * must know all networks accessible).
+ */
+
+/* for compatibility with glibc net/if.h */
+#if __UAPI_DEF_IF_IFCONF
+struct ifconf {
+ int ifc_len; /* size of buffer */
+ union {
+ char *ifcu_buf;
+ struct ifreq *ifcu_req;
+ } ifc_ifcu;
+};
+#endif /* __UAPI_DEF_IF_IFCONF */
+
+#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
+#define ifc_req ifc_ifcu.ifcu_req /* array of structures */
+
+#endif /* _LINUX_IF_H */
diff --git a/include/linux-private/linux/if_addr.h b/include/linux-private/linux/if_addr.h
index 7d4de855..a924606f 100644
--- a/include/linux-private/linux/if_addr.h
+++ b/include/linux-private/linux/if_addr.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_IF_ADDR_H
#define __LINUX_IF_ADDR_H
@@ -32,6 +33,7 @@ enum {
IFA_CACHEINFO,
IFA_MULTICAST,
IFA_FLAGS,
+ IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */
__IFA_MAX,
};
@@ -50,6 +52,8 @@ enum {
#define IFA_F_PERMANENT 0x80
#define IFA_F_MANAGETEMPADDR 0x100
#define IFA_F_NOPREFIXROUTE 0x200
+#define IFA_F_MCAUTOJOIN 0x400
+#define IFA_F_STABLE_PRIVACY 0x800
struct ifa_cacheinfo {
__u32 ifa_prefered;
@@ -58,4 +62,8 @@ struct ifa_cacheinfo {
__u32 tstamp; /* updated timestamp, hundredths of seconds */
};
+/* backwards compatibility for userspace */
+#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
+#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
+
#endif
diff --git a/include/linux-private/linux/if_arp.h b/include/linux-private/linux/if_arp.h
index e04cd2cd..cd136a6f 100644
--- a/include/linux-private/linux/if_arp.h
+++ b/include/linux-private/linux/if_arp.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
@@ -59,6 +60,7 @@
#define ARPHRD_LAPB 516 /* LAPB */
#define ARPHRD_DDCMP 517 /* Digital's DDCMP protocol */
#define ARPHRD_RAWHDLC 518 /* Raw HDLC */
+#define ARPHRD_RAWIP 519 /* Raw IP */
#define ARPHRD_TUNNEL 768 /* IPIP tunnel */
#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */
@@ -87,10 +89,15 @@
#define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */
#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */
#define ARPHRD_IEEE802154 804
+#define ARPHRD_IEEE802154_MONITOR 805 /* IEEE 802.15.4 network monitor */
#define ARPHRD_PHONET 820 /* PhoNet media type */
#define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */
#define ARPHRD_CAIF 822 /* CAIF media type */
+#define ARPHRD_IP6GRE 823 /* GRE over IPv6 */
+#define ARPHRD_NETLINK 824 /* Netlink header */
+#define ARPHRD_6LOWPAN 825 /* IPv6 over LoWPAN */
+#define ARPHRD_VSOCKMON 826 /* Vsock monitor header */
#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
#define ARPHRD_NONE 0xFFFE /* zero header length */
@@ -153,4 +160,5 @@ struct arphdr {
};
-#endif /* _LINUX_IF_ARP_H */
+
+#endif /* _LINUX_IF_ARP_H */
diff --git a/include/linux-private/linux/if_bad.h b/include/linux-private/linux/if_bad.h
deleted file mode 100644
index bbb3ea37..00000000
--- a/include/linux-private/linux/if_bad.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Global definitions for the INET interface module.
- *
- * Version: @(#)if.h 1.0.2 04/18/93
- *
- * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988
- * Ross Biro
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#ifndef _LINUX_IF_H
-#define _LINUX_IF_H
-
-#define IFNAMSIZ 16
-#define IFALIASZ 256
-
-/* Standard interface flags (netdevice->flags). */
-#define IFF_UP 0x1 /* interface is up */
-#define IFF_BROADCAST 0x2 /* broadcast address valid */
-#define IFF_DEBUG 0x4 /* turn on debugging */
-#define IFF_LOOPBACK 0x8 /* is a loopback net */
-#define IFF_POINTOPOINT 0x10 /* interface is has p-p link */
-#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */
-#define IFF_RUNNING 0x40 /* interface RFC2863 OPER_UP */
-#define IFF_NOARP 0x80 /* no ARP protocol */
-#define IFF_PROMISC 0x100 /* receive all packets */
-#define IFF_ALLMULTI 0x200 /* receive all multicast packets*/
-
-#define IFF_MASTER 0x400 /* master of a load balancer */
-#define IFF_SLAVE 0x800 /* slave of a load balancer */
-
-#define IFF_MULTICAST 0x1000 /* Supports multicast */
-
-#define IFF_PORTSEL 0x2000 /* can set media type */
-#define IFF_AUTOMEDIA 0x4000 /* auto media select active */
-#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/
-
-#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
-#define IFF_DORMANT 0x20000 /* driver signals dormant */
-
-#define IFF_ECHO 0x40000 /* echo sent packets */
-
-#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\
- IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT)
-
-/* Private (from user) interface flags (netdevice->priv_flags). */
-#define IFF_802_1Q_VLAN 0x1 /* 802.1Q VLAN device. */
-#define IFF_EBRIDGE 0x2 /* Ethernet bridging device. */
-#define IFF_SLAVE_INACTIVE 0x4 /* bonding slave not the curr. active */
-#define IFF_MASTER_8023AD 0x8 /* bonding master, 802.3ad. */
-#define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */
-#define IFF_BONDING 0x20 /* bonding master or slave */
-#define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */
-#define IFF_ISATAP 0x80 /* ISATAP interface (RFC4214) */
-#define IFF_MASTER_ARPMON 0x100 /* bonding master, ARP mon in use */
-#define IFF_WAN_HDLC 0x200 /* WAN HDLC device */
-#define IFF_XMIT_DST_RELEASE 0x400 /* dev_hard_start_xmit() is allowed to
- * release skb->dst
- */
-#define IFF_DONT_BRIDGE 0x800 /* disallow bridging this ether dev */
-#define IFF_IN_NETPOLL 0x1000 /* whether we are processing netpoll */
-#define IFF_DISABLE_NETPOLL 0x2000 /* disable netpoll at run-time */
-#define IFF_MACVLAN_PORT 0x4000 /* device used as macvlan port */
-#define IFF_BRIDGE_PORT 0x8000 /* device used as bridge port */
-#define IFF_OVS_DATAPATH 0x10000 /* device used as Open vSwitch
- * datapath port */
-
-#define IF_GET_IFACE 0x0001 /* for querying only */
-#define IF_GET_PROTO 0x0002
-
-/* For definitions see hdlc.h */
-#define IF_IFACE_V35 0x1000 /* V.35 serial interface */
-#define IF_IFACE_V24 0x1001 /* V.24 serial interface */
-#define IF_IFACE_X21 0x1002 /* X.21 serial interface */
-#define IF_IFACE_T1 0x1003 /* T1 telco serial interface */
-#define IF_IFACE_E1 0x1004 /* E1 telco serial interface */
-#define IF_IFACE_SYNC_SERIAL 0x1005 /* can't be set by software */
-#define IF_IFACE_X21D 0x1006 /* X.21 Dual Clocking (FarSite) */
-
-/* For definitions see hdlc.h */
-#define IF_PROTO_HDLC 0x2000 /* raw HDLC protocol */
-#define IF_PROTO_PPP 0x2001 /* PPP protocol */
-#define IF_PROTO_CISCO 0x2002 /* Cisco HDLC protocol */
-#define IF_PROTO_FR 0x2003 /* Frame Relay protocol */
-#define IF_PROTO_FR_ADD_PVC 0x2004 /* Create FR PVC */
-#define IF_PROTO_FR_DEL_PVC 0x2005 /* Delete FR PVC */
-#define IF_PROTO_X25 0x2006 /* X.25 */
-#define IF_PROTO_HDLC_ETH 0x2007 /* raw HDLC, Ethernet emulation */
-#define IF_PROTO_FR_ADD_ETH_PVC 0x2008 /* Create FR Ethernet-bridged PVC */
-#define IF_PROTO_FR_DEL_ETH_PVC 0x2009 /* Delete FR Ethernet-bridged PVC */
-#define IF_PROTO_FR_PVC 0x200A /* for reading PVC status */
-#define IF_PROTO_FR_ETH_PVC 0x200B
-#define IF_PROTO_RAW 0x200C /* RAW Socket */
-
-/* RFC 2863 operational status */
-enum {
- IF_OPER_UNKNOWN,
- IF_OPER_NOTPRESENT,
- IF_OPER_DOWN,
- IF_OPER_LOWERLAYERDOWN,
- IF_OPER_TESTING,
- IF_OPER_DORMANT,
- IF_OPER_UP,
-};
-
-/* link modes */
-enum {
- IF_LINK_MODE_DEFAULT,
- IF_LINK_MODE_DORMANT, /* limit upward transition to dormant */
-};
-
-/* carrier state */
-enum {
- IF_CARRIER_DOWN,
- IF_CARRIER_UP
-};
-
-/*
- * Device mapping structure. I'd just gone off and designed a
- * beautiful scheme using only loadable modules with arguments
- * for driver options and along come the PCMCIA people 8)
- *
- * Ah well. The get() side of this is good for WDSETUP, and it'll
- * be handy for debugging things. The set side is fine for now and
- * being very small might be worth keeping for clean configuration.
- */
-
-struct ifmap {
- unsigned long mem_start;
- unsigned long mem_end;
- unsigned short base_addr;
- unsigned char irq;
- unsigned char dma;
- unsigned char port;
- /* 3 bytes spare */
-};
-
-#endif /* _LINUX_IF_H */
diff --git a/include/linux-private/linux/if_bridge.h b/include/linux-private/linux/if_bridge.h
index 5db29751..bdfecf94 100644
--- a/include/linux-private/linux/if_bridge.h
+++ b/include/linux-private/linux/if_bridge.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* Linux ethernet bridge
*
@@ -10,10 +11,12 @@
* 2 of the License, or (at your option) any later version.
*/
-#ifndef _UAPI_LINUX_IF_BRIDGE_H
-#define _UAPI_LINUX_IF_BRIDGE_H
+#ifndef _LINUX_IF_BRIDGE_H
+#define _LINUX_IF_BRIDGE_H
#include <linux/types.h>
+#include <linux/if_ether.h>
+#include <linux/in6.h>
#define SYSFS_BRIDGE_ATTR "bridge"
#define SYSFS_BRIDGE_FDB "brforward"
@@ -88,7 +91,7 @@ struct __port_info {
};
struct __fdb_entry {
- __u8 mac_addr[6];
+ __u8 mac_addr[ETH_ALEN];
__u8 port_no;
__u8 is_local;
__u32 ageing_timer_value;
@@ -103,28 +106,70 @@ struct __fdb_entry {
#define BRIDGE_MODE_VEB 0 /* Default loopback mode */
#define BRIDGE_MODE_VEPA 1 /* 802.1Qbg defined VEPA mode */
+#define BRIDGE_MODE_UNDEF 0xFFFF /* mode undefined */
/* Bridge management nested attributes
* [IFLA_AF_SPEC] = {
* [IFLA_BRIDGE_FLAGS]
* [IFLA_BRIDGE_MODE]
+ * [IFLA_BRIDGE_VLAN_INFO]
* }
*/
enum {
IFLA_BRIDGE_FLAGS,
IFLA_BRIDGE_MODE,
+ IFLA_BRIDGE_VLAN_INFO,
+ IFLA_BRIDGE_VLAN_TUNNEL_INFO,
__IFLA_BRIDGE_MAX,
};
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
+#define BRIDGE_VLAN_INFO_MASTER (1<<0) /* Operate on Bridge device as well */
+#define BRIDGE_VLAN_INFO_PVID (1<<1) /* VLAN is PVID, ingress untagged */
+#define BRIDGE_VLAN_INFO_UNTAGGED (1<<2) /* VLAN egresses untagged */
+#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */
+#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
+#define BRIDGE_VLAN_INFO_BRENTRY (1<<5) /* Global bridge VLAN entry */
+
+struct bridge_vlan_info {
+ __u16 flags;
+ __u16 vid;
+};
+
+enum {
+ IFLA_BRIDGE_VLAN_TUNNEL_UNSPEC,
+ IFLA_BRIDGE_VLAN_TUNNEL_ID,
+ IFLA_BRIDGE_VLAN_TUNNEL_VID,
+ IFLA_BRIDGE_VLAN_TUNNEL_FLAGS,
+ __IFLA_BRIDGE_VLAN_TUNNEL_MAX,
+};
+
+#define IFLA_BRIDGE_VLAN_TUNNEL_MAX (__IFLA_BRIDGE_VLAN_TUNNEL_MAX - 1)
+
+struct bridge_vlan_xstats {
+ __u64 rx_bytes;
+ __u64 rx_packets;
+ __u64 tx_bytes;
+ __u64 tx_packets;
+ __u16 vid;
+ __u16 flags;
+ __u32 pad2;
+};
+
/* Bridge multicast database attributes
* [MDBA_MDB] = {
* [MDBA_MDB_ENTRY] = {
- * [MDBA_MDB_ENTRY_INFO]
+ * [MDBA_MDB_ENTRY_INFO] {
+ * struct br_mdb_entry
+ * [MDBA_MDB_EATTR attributes]
+ * }
* }
* }
* [MDBA_ROUTER] = {
- * [MDBA_ROUTER_PORT]
+ * [MDBA_ROUTER_PORT] = {
+ * u32 ifindex
+ * [MDBA_ROUTER_PATTR attributes]
+ * }
* }
*/
enum {
@@ -149,6 +194,22 @@ enum {
};
#define MDBA_MDB_ENTRY_MAX (__MDBA_MDB_ENTRY_MAX - 1)
+/* per mdb entry additional attributes */
+enum {
+ MDBA_MDB_EATTR_UNSPEC,
+ MDBA_MDB_EATTR_TIMER,
+ __MDBA_MDB_EATTR_MAX
+};
+#define MDBA_MDB_EATTR_MAX (__MDBA_MDB_EATTR_MAX - 1)
+
+/* multicast router types */
+enum {
+ MDB_RTR_TYPE_DISABLED,
+ MDB_RTR_TYPE_TEMP_QUERY,
+ MDB_RTR_TYPE_PERM,
+ MDB_RTR_TYPE_TEMP
+};
+
enum {
MDBA_ROUTER_UNSPEC,
MDBA_ROUTER_PORT,
@@ -156,6 +217,15 @@ enum {
};
#define MDBA_ROUTER_MAX (__MDBA_ROUTER_MAX - 1)
+/* router port attributes */
+enum {
+ MDBA_ROUTER_PATTR_UNSPEC,
+ MDBA_ROUTER_PATTR_TIMER,
+ MDBA_ROUTER_PATTR_TYPE,
+ __MDBA_ROUTER_PATTR_MAX
+};
+#define MDBA_ROUTER_PATTR_MAX (__MDBA_ROUTER_PATTR_MAX - 1)
+
struct br_port_msg {
__u8 family;
__u32 ifindex;
@@ -166,6 +236,9 @@ struct br_mdb_entry {
#define MDB_TEMPORARY 0
#define MDB_PERMANENT 1
__u8 state;
+#define MDB_FLAGS_OFFLOAD (1 << 0)
+ __u8 flags;
+ __u16 vid;
struct {
union {
__be32 ip4;
@@ -182,4 +255,41 @@ enum {
};
#define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1)
-#endif /* _UAPI_LINUX_IF_BRIDGE_H */
+/* Embedded inside LINK_XSTATS_TYPE_BRIDGE */
+enum {
+ BRIDGE_XSTATS_UNSPEC,
+ BRIDGE_XSTATS_VLAN,
+ BRIDGE_XSTATS_MCAST,
+ BRIDGE_XSTATS_PAD,
+ __BRIDGE_XSTATS_MAX
+};
+#define BRIDGE_XSTATS_MAX (__BRIDGE_XSTATS_MAX - 1)
+
+enum {
+ BR_MCAST_DIR_RX,
+ BR_MCAST_DIR_TX,
+ BR_MCAST_DIR_SIZE
+};
+
+/* IGMP/MLD statistics */
+struct br_mcast_stats {
+ __u64 igmp_v1queries[BR_MCAST_DIR_SIZE];
+ __u64 igmp_v2queries[BR_MCAST_DIR_SIZE];
+ __u64 igmp_v3queries[BR_MCAST_DIR_SIZE];
+ __u64 igmp_leaves[BR_MCAST_DIR_SIZE];
+ __u64 igmp_v1reports[BR_MCAST_DIR_SIZE];
+ __u64 igmp_v2reports[BR_MCAST_DIR_SIZE];
+ __u64 igmp_v3reports[BR_MCAST_DIR_SIZE];
+ __u64 igmp_parse_errors;
+
+ __u64 mld_v1queries[BR_MCAST_DIR_SIZE];
+ __u64 mld_v2queries[BR_MCAST_DIR_SIZE];
+ __u64 mld_leaves[BR_MCAST_DIR_SIZE];
+ __u64 mld_v1reports[BR_MCAST_DIR_SIZE];
+ __u64 mld_v2reports[BR_MCAST_DIR_SIZE];
+ __u64 mld_parse_errors;
+
+ __u64 mcast_bytes[BR_MCAST_DIR_SIZE];
+ __u64 mcast_packets[BR_MCAST_DIR_SIZE];
+};
+#endif /* _LINUX_IF_BRIDGE_H */
diff --git a/include/linux-private/linux/if_ether.h b/include/linux-private/linux/if_ether.h
index a6af32d7..8c36f63e 100644
--- a/include/linux-private/linux/if_ether.h
+++ b/include/linux-private/linux/if_ether.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
@@ -29,12 +30,16 @@
*/
#define ETH_ALEN 6 /* Octets in one ethernet addr */
+#define ETH_TLEN 2 /* Octets in ethernet type field */
#define ETH_HLEN 14 /* Total octets in header. */
#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
#define ETH_DATA_LEN 1500 /* Max. octets in payload */
#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
#define ETH_FCS_LEN 4 /* Octets in the FCS */
+#define ETH_MIN_MTU 68 /* Min IPv4 MTU per RFC791 */
+#define ETH_MAX_MTU 0xFFFFU /* 65535, same as IP_MAX_MTU */
+
/*
* These are the defined Ethernet Protocol ID's.
*/
@@ -42,12 +47,15 @@
#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
#define ETH_P_PUP 0x0200 /* Xerox PUP packet */
#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */
+#define ETH_P_TSN 0x22F0 /* TSN (IEEE 1722) packet */
+#define ETH_P_ERSPAN2 0x22EB /* ERSPAN version 2 (type III) */
#define ETH_P_IP 0x0800 /* Internet Protocol packet */
#define ETH_P_X25 0x0805 /* CCITT X.25 */
#define ETH_P_ARP 0x0806 /* Address Resolution packet */
#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */
#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP Addr Trans packet */
+#define ETH_P_BATMAN 0x4305 /* B.A.T.M.A.N.-Advanced packet [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_DEC 0x6000 /* DEC Assigned proto */
#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */
#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */
@@ -61,28 +69,51 @@
#define ETH_P_ATALK 0x809B /* Appletalk DDP */
#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
+#define ETH_P_ERSPAN 0x88BE /* ERSPAN type II */
#define ETH_P_IPX 0x8137 /* IPX over DIX */
#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
#define ETH_P_PAUSE 0x8808 /* IEEE Pause frames. See 802.3 31B */
#define ETH_P_SLOW 0x8809 /* Slow Protocol. See 802.3ad 43B */
#define ETH_P_WCCP 0x883E /* Web-cache coordination protocol
* defined in draft-wilson-wrec-wccp-v2-00.txt */
-#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */
-#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */
#define ETH_P_MPLS_UC 0x8847 /* MPLS Unicast traffic */
#define ETH_P_MPLS_MC 0x8848 /* MPLS Multicast traffic */
#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */
+#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */
+#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */
#define ETH_P_LINK_CTL 0x886c /* HPNA, wlan link local tunnel */
#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport
* over Ethernet
*/
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
#define ETH_P_AOE 0x88A2 /* ATA over Ethernet */
+#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
+#define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */
+#define ETH_P_PREAUTH 0x88C7 /* 802.11 Preauthentication */
#define ETH_P_TIPC 0x88CA /* TIPC */
+#define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */
+#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */
+#define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */
#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */
+#define ETH_P_NCSI 0x88F8 /* NCSI protocol */
+#define ETH_P_PRP 0x88FB /* IEC 62439-3 PRP/HSRv0 */
#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */
+#define ETH_P_IBOE 0x8915 /* Infiniband over Ethernet */
+#define ETH_P_TDLS 0x890D /* TDLS */
#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */
+#define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent Handover Protocol */
+#define ETH_P_HSR 0x892F /* IEC 62439-3 HSRv1 */
+#define ETH_P_NSH 0x894F /* Network Service Header */
+#define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */
+#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_IFE 0xED3E /* ForCES inter-FE LFB type */
+#define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */
+
+#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less than this value
+ * then the frame is Ethernet II. Else it is 802.3 */
/*
* Non DIX types. Won't clash for 1500 types.
@@ -97,7 +128,8 @@
#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/
#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */
#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
-#define ETH_P_CAN 0x000C /* Controller Area Network */
+#define ETH_P_CAN 0x000C /* CAN: Controller Area Network */
+#define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/
#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
@@ -111,15 +143,27 @@
#define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */
#define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */
#define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */
+#define ETH_P_XDSA 0x00F8 /* Multiplexed DSA protocol */
+#define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and
+ * aggregation protocol
+ */
/*
* This is an Ethernet frame header.
*/
+/* allow libcs like musl to deactivate this, glibc does not implement this. */
+#ifndef __UAPI_DEF_ETHHDR
+#define __UAPI_DEF_ETHHDR 1
+#endif
+
+#if __UAPI_DEF_ETHHDR
struct ethhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
__be16 h_proto; /* packet type ID field */
} __attribute__((packed));
+#endif
+
-#endif /* _LINUX_IF_ETHER_H */
+#endif /* _LINUX_IF_ETHER_H */
diff --git a/include/linux-private/linux/if_link.h b/include/linux-private/linux/if_link.h
index 8b849394..f4a97151 100644
--- a/include/linux-private/linux/if_link.h
+++ b/include/linux-private/linux/if_link.h
@@ -1,5 +1,6 @@
-#ifndef _UAPI_LINUX_IF_LINK_H
-#define _UAPI_LINUX_IF_LINK_H
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_IF_LINK_H
+#define _LINUX_IF_LINK_H
#include <linux/types.h>
#include <linux/netlink.h>
@@ -35,6 +36,8 @@ struct rtnl_link_stats {
/* for cslip etc */
__u32 rx_compressed;
__u32 tx_compressed;
+
+ __u32 rx_nohandler; /* dropped, no handler found */
};
/* The main device statistics structure */
@@ -68,6 +71,8 @@ struct rtnl_link_stats64 {
/* for cslip etc */
__u64 rx_compressed;
__u64 tx_compressed;
+
+ __u64 rx_nohandler; /* dropped, no handler found */
};
/* The struct should be in sync with struct ifmap */
@@ -144,12 +149,33 @@ enum {
IFLA_NUM_RX_QUEUES,
IFLA_CARRIER,
IFLA_PHYS_PORT_ID,
+ IFLA_CARRIER_CHANGES,
+ IFLA_PHYS_SWITCH_ID,
+ IFLA_LINK_NETNSID,
+ IFLA_PHYS_PORT_NAME,
+ IFLA_PROTO_DOWN,
+ IFLA_GSO_MAX_SEGS,
+ IFLA_GSO_MAX_SIZE,
+ IFLA_PAD,
+ IFLA_XDP,
+ IFLA_EVENT,
+ IFLA_NEW_NETNSID,
+ IFLA_IF_NETNSID,
+ IFLA_CARRIER_UP_COUNT,
+ IFLA_CARRIER_DOWN_COUNT,
+ IFLA_NEW_IFINDEX,
+ IFLA_MIN_MTU,
+ IFLA_MAX_MTU,
__IFLA_MAX
};
#define IFLA_MAX (__IFLA_MAX - 1)
+/* backwards compatibility for userspace */
+#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
+#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
+
enum {
IFLA_INET_UNSPEC,
IFLA_INET_CONF,
@@ -196,11 +222,78 @@ enum {
IFLA_INET6_MCAST, /* MC things. What of them? */
IFLA_INET6_CACHEINFO, /* time values and max reasm size */
IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */
+ IFLA_INET6_TOKEN, /* device token */
+ IFLA_INET6_ADDR_GEN_MODE, /* implicit address generator mode */
__IFLA_INET6_MAX
};
#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+enum in6_addr_gen_mode {
+ IN6_ADDR_GEN_MODE_EUI64,
+ IN6_ADDR_GEN_MODE_NONE,
+ IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
+ IN6_ADDR_GEN_MODE_RANDOM,
+};
+
+/* Bridge section */
+
+enum {
+ IFLA_BR_UNSPEC,
+ IFLA_BR_FORWARD_DELAY,
+ IFLA_BR_HELLO_TIME,
+ IFLA_BR_MAX_AGE,
+ IFLA_BR_AGEING_TIME,
+ IFLA_BR_STP_STATE,
+ IFLA_BR_PRIORITY,
+ IFLA_BR_VLAN_FILTERING,
+ IFLA_BR_VLAN_PROTOCOL,
+ IFLA_BR_GROUP_FWD_MASK,
+ IFLA_BR_ROOT_ID,
+ IFLA_BR_BRIDGE_ID,
+ IFLA_BR_ROOT_PORT,
+ IFLA_BR_ROOT_PATH_COST,
+ IFLA_BR_TOPOLOGY_CHANGE,
+ IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
+ IFLA_BR_HELLO_TIMER,
+ IFLA_BR_TCN_TIMER,
+ IFLA_BR_TOPOLOGY_CHANGE_TIMER,
+ IFLA_BR_GC_TIMER,
+ IFLA_BR_GROUP_ADDR,
+ IFLA_BR_FDB_FLUSH,
+ IFLA_BR_MCAST_ROUTER,
+ IFLA_BR_MCAST_SNOOPING,
+ IFLA_BR_MCAST_QUERY_USE_IFADDR,
+ IFLA_BR_MCAST_QUERIER,
+ IFLA_BR_MCAST_HASH_ELASTICITY,
+ IFLA_BR_MCAST_HASH_MAX,
+ IFLA_BR_MCAST_LAST_MEMBER_CNT,
+ IFLA_BR_MCAST_STARTUP_QUERY_CNT,
+ IFLA_BR_MCAST_LAST_MEMBER_INTVL,
+ IFLA_BR_MCAST_MEMBERSHIP_INTVL,
+ IFLA_BR_MCAST_QUERIER_INTVL,
+ IFLA_BR_MCAST_QUERY_INTVL,
+ IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
+ IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
+ IFLA_BR_NF_CALL_IPTABLES,
+ IFLA_BR_NF_CALL_IP6TABLES,
+ IFLA_BR_NF_CALL_ARPTABLES,
+ IFLA_BR_VLAN_DEFAULT_PVID,
+ IFLA_BR_PAD,
+ IFLA_BR_VLAN_STATS_ENABLED,
+ IFLA_BR_MCAST_STATS_ENABLED,
+ IFLA_BR_MCAST_IGMP_VERSION,
+ IFLA_BR_MCAST_MLD_VERSION,
+ __IFLA_BR_MAX,
+};
+
+#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
+
+struct ifla_bridge_id {
+ __u8 prio[2];
+ __u8 addr[6]; /* ETH_ALEN */
+};
+
enum {
BRIDGE_MODE_UNSPEC,
BRIDGE_MODE_HAIRPIN,
@@ -215,6 +308,33 @@ enum {
IFLA_BRPORT_GUARD, /* bpdu guard */
IFLA_BRPORT_PROTECT, /* root port protection */
IFLA_BRPORT_FAST_LEAVE, /* multicast fast leave */
+ IFLA_BRPORT_LEARNING, /* mac learning */
+ IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */
+ IFLA_BRPORT_PROXYARP, /* proxy ARP */
+ IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */
+ IFLA_BRPORT_PROXYARP_WIFI, /* proxy ARP for Wi-Fi */
+ IFLA_BRPORT_ROOT_ID, /* designated root */
+ IFLA_BRPORT_BRIDGE_ID, /* designated bridge */
+ IFLA_BRPORT_DESIGNATED_PORT,
+ IFLA_BRPORT_DESIGNATED_COST,
+ IFLA_BRPORT_ID,
+ IFLA_BRPORT_NO,
+ IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
+ IFLA_BRPORT_CONFIG_PENDING,
+ IFLA_BRPORT_MESSAGE_AGE_TIMER,
+ IFLA_BRPORT_FORWARD_DELAY_TIMER,
+ IFLA_BRPORT_HOLD_TIMER,
+ IFLA_BRPORT_FLUSH,
+ IFLA_BRPORT_MULTICAST_ROUTER,
+ IFLA_BRPORT_PAD,
+ IFLA_BRPORT_MCAST_FLOOD,
+ IFLA_BRPORT_MCAST_TO_UCAST,
+ IFLA_BRPORT_VLAN_TUNNEL,
+ IFLA_BRPORT_BCAST_FLOOD,
+ IFLA_BRPORT_GROUP_FWD_MASK,
+ IFLA_BRPORT_NEIGH_SUPPRESS,
+ IFLA_BRPORT_ISOLATED,
+ IFLA_BRPORT_BACKUP_PORT,
__IFLA_BRPORT_MAX
};
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
@@ -231,6 +351,8 @@ enum {
IFLA_INFO_KIND,
IFLA_INFO_DATA,
IFLA_INFO_XSTATS,
+ IFLA_INFO_SLAVE_KIND,
+ IFLA_INFO_SLAVE_DATA,
__IFLA_INFO_MAX,
};
@@ -273,6 +395,10 @@ enum {
IFLA_MACVLAN_UNSPEC,
IFLA_MACVLAN_MODE,
IFLA_MACVLAN_FLAGS,
+ IFLA_MACVLAN_MACADDR_MODE,
+ IFLA_MACVLAN_MACADDR,
+ IFLA_MACVLAN_MACADDR_DATA,
+ IFLA_MACVLAN_MACADDR_COUNT,
__IFLA_MACVLAN_MAX,
};
@@ -283,15 +409,100 @@ enum macvlan_mode {
MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */
MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */
MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */
+ MACVLAN_MODE_SOURCE = 16,/* use source MAC address list to assign */
+};
+
+enum macvlan_macaddr_mode {
+ MACVLAN_MACADDR_ADD,
+ MACVLAN_MACADDR_DEL,
+ MACVLAN_MACADDR_FLUSH,
+ MACVLAN_MACADDR_SET,
};
#define MACVLAN_FLAG_NOPROMISC 1
+/* VRF section */
+enum {
+ IFLA_VRF_UNSPEC,
+ IFLA_VRF_TABLE,
+ __IFLA_VRF_MAX
+};
+
+#define IFLA_VRF_MAX (__IFLA_VRF_MAX - 1)
+
+enum {
+ IFLA_VRF_PORT_UNSPEC,
+ IFLA_VRF_PORT_TABLE,
+ __IFLA_VRF_PORT_MAX
+};
+
+#define IFLA_VRF_PORT_MAX (__IFLA_VRF_PORT_MAX - 1)
+
+/* MACSEC section */
+enum {
+ IFLA_MACSEC_UNSPEC,
+ IFLA_MACSEC_SCI,
+ IFLA_MACSEC_PORT,
+ IFLA_MACSEC_ICV_LEN,
+ IFLA_MACSEC_CIPHER_SUITE,
+ IFLA_MACSEC_WINDOW,
+ IFLA_MACSEC_ENCODING_SA,
+ IFLA_MACSEC_ENCRYPT,
+ IFLA_MACSEC_PROTECT,
+ IFLA_MACSEC_INC_SCI,
+ IFLA_MACSEC_ES,
+ IFLA_MACSEC_SCB,
+ IFLA_MACSEC_REPLAY_PROTECT,
+ IFLA_MACSEC_VALIDATION,
+ IFLA_MACSEC_PAD,
+ __IFLA_MACSEC_MAX,
+};
+
+#define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1)
+
+/* XFRM section */
+enum {
+ IFLA_XFRM_UNSPEC,
+ IFLA_XFRM_LINK,
+ IFLA_XFRM_IF_ID,
+ __IFLA_XFRM_MAX
+};
+
+#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1)
+
+enum macsec_validation_type {
+ MACSEC_VALIDATE_DISABLED = 0,
+ MACSEC_VALIDATE_CHECK = 1,
+ MACSEC_VALIDATE_STRICT = 2,
+ __MACSEC_VALIDATE_END,
+ MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1,
+};
+
+/* IPVLAN section */
+enum {
+ IFLA_IPVLAN_UNSPEC,
+ IFLA_IPVLAN_MODE,
+ IFLA_IPVLAN_FLAGS,
+ __IFLA_IPVLAN_MAX
+};
+
+#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1)
+
+enum ipvlan_mode {
+ IPVLAN_MODE_L2 = 0,
+ IPVLAN_MODE_L3,
+ IPVLAN_MODE_L3S,
+ IPVLAN_MODE_MAX
+};
+
+#define IPVLAN_F_PRIVATE 0x01
+#define IPVLAN_F_VEPA 0x02
+
/* VXLAN section */
enum {
IFLA_VXLAN_UNSPEC,
IFLA_VXLAN_ID,
- IFLA_VXLAN_GROUP,
+ IFLA_VXLAN_GROUP, /* group or remote address */
IFLA_VXLAN_LINK,
IFLA_VXLAN_LOCAL,
IFLA_VXLAN_TTL,
@@ -299,11 +510,25 @@ enum {
IFLA_VXLAN_LEARNING,
IFLA_VXLAN_AGEING,
IFLA_VXLAN_LIMIT,
- IFLA_VXLAN_PORT_RANGE,
+ IFLA_VXLAN_PORT_RANGE, /* source port */
IFLA_VXLAN_PROXY,
IFLA_VXLAN_RSC,
IFLA_VXLAN_L2MISS,
IFLA_VXLAN_L3MISS,
+ IFLA_VXLAN_PORT, /* destination port */
+ IFLA_VXLAN_GROUP6,
+ IFLA_VXLAN_LOCAL6,
+ IFLA_VXLAN_UDP_CSUM,
+ IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
+ IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
+ IFLA_VXLAN_REMCSUM_TX,
+ IFLA_VXLAN_REMCSUM_RX,
+ IFLA_VXLAN_GBP,
+ IFLA_VXLAN_REMCSUM_NOPARTIAL,
+ IFLA_VXLAN_COLLECT_METADATA,
+ IFLA_VXLAN_LABEL,
+ IFLA_VXLAN_GPE,
+ IFLA_VXLAN_TTL_INHERIT,
__IFLA_VXLAN_MAX
};
#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1)
@@ -313,14 +538,112 @@ struct ifla_vxlan_port_range {
__be16 high;
};
+/* GENEVE section */
enum {
- VETH_INFO_UNSPEC,
- VETH_INFO_PEER,
+ IFLA_GENEVE_UNSPEC,
+ IFLA_GENEVE_ID,
+ IFLA_GENEVE_REMOTE,
+ IFLA_GENEVE_TTL,
+ IFLA_GENEVE_TOS,
+ IFLA_GENEVE_PORT, /* destination port */
+ IFLA_GENEVE_COLLECT_METADATA,
+ IFLA_GENEVE_REMOTE6,
+ IFLA_GENEVE_UDP_CSUM,
+ IFLA_GENEVE_UDP_ZERO_CSUM6_TX,
+ IFLA_GENEVE_UDP_ZERO_CSUM6_RX,
+ IFLA_GENEVE_LABEL,
+ __IFLA_GENEVE_MAX
+};
+#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1)
+
+/* PPP section */
+enum {
+ IFLA_PPP_UNSPEC,
+ IFLA_PPP_DEV_FD,
+ __IFLA_PPP_MAX
+};
+#define IFLA_PPP_MAX (__IFLA_PPP_MAX - 1)
+
+/* GTP section */
- __VETH_INFO_MAX
-#define VETH_INFO_MAX (__VETH_INFO_MAX - 1)
+enum ifla_gtp_role {
+ GTP_ROLE_GGSN = 0,
+ GTP_ROLE_SGSN,
};
+enum {
+ IFLA_GTP_UNSPEC,
+ IFLA_GTP_FD0,
+ IFLA_GTP_FD1,
+ IFLA_GTP_PDP_HASHSIZE,
+ IFLA_GTP_ROLE,
+ __IFLA_GTP_MAX,
+};
+#define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1)
+
+/* Bonding section */
+
+enum {
+ IFLA_BOND_UNSPEC,
+ IFLA_BOND_MODE,
+ IFLA_BOND_ACTIVE_SLAVE,
+ IFLA_BOND_MIIMON,
+ IFLA_BOND_UPDELAY,
+ IFLA_BOND_DOWNDELAY,
+ IFLA_BOND_USE_CARRIER,
+ IFLA_BOND_ARP_INTERVAL,
+ IFLA_BOND_ARP_IP_TARGET,
+ IFLA_BOND_ARP_VALIDATE,
+ IFLA_BOND_ARP_ALL_TARGETS,
+ IFLA_BOND_PRIMARY,
+ IFLA_BOND_PRIMARY_RESELECT,
+ IFLA_BOND_FAIL_OVER_MAC,
+ IFLA_BOND_XMIT_HASH_POLICY,
+ IFLA_BOND_RESEND_IGMP,
+ IFLA_BOND_NUM_PEER_NOTIF,
+ IFLA_BOND_ALL_SLAVES_ACTIVE,
+ IFLA_BOND_MIN_LINKS,
+ IFLA_BOND_LP_INTERVAL,
+ IFLA_BOND_PACKETS_PER_SLAVE,
+ IFLA_BOND_AD_LACP_RATE,
+ IFLA_BOND_AD_SELECT,
+ IFLA_BOND_AD_INFO,
+ IFLA_BOND_AD_ACTOR_SYS_PRIO,
+ IFLA_BOND_AD_USER_PORT_KEY,
+ IFLA_BOND_AD_ACTOR_SYSTEM,
+ IFLA_BOND_TLB_DYNAMIC_LB,
+ __IFLA_BOND_MAX,
+};
+
+#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1)
+
+enum {
+ IFLA_BOND_AD_INFO_UNSPEC,
+ IFLA_BOND_AD_INFO_AGGREGATOR,
+ IFLA_BOND_AD_INFO_NUM_PORTS,
+ IFLA_BOND_AD_INFO_ACTOR_KEY,
+ IFLA_BOND_AD_INFO_PARTNER_KEY,
+ IFLA_BOND_AD_INFO_PARTNER_MAC,
+ __IFLA_BOND_AD_INFO_MAX,
+};
+
+#define IFLA_BOND_AD_INFO_MAX (__IFLA_BOND_AD_INFO_MAX - 1)
+
+enum {
+ IFLA_BOND_SLAVE_UNSPEC,
+ IFLA_BOND_SLAVE_STATE,
+ IFLA_BOND_SLAVE_MII_STATUS,
+ IFLA_BOND_SLAVE_LINK_FAILURE_COUNT,
+ IFLA_BOND_SLAVE_PERM_HWADDR,
+ IFLA_BOND_SLAVE_QUEUE_ID,
+ IFLA_BOND_SLAVE_AD_AGGREGATOR_ID,
+ IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE,
+ IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE,
+ __IFLA_BOND_SLAVE_MAX,
+};
+
+#define IFLA_BOND_SLAVE_MAX (__IFLA_BOND_SLAVE_MAX - 1)
+
/* SR-IOV virtual function management section */
enum {
@@ -334,9 +657,19 @@ enum {
enum {
IFLA_VF_UNSPEC,
IFLA_VF_MAC, /* Hardware queue specific attributes */
- IFLA_VF_VLAN,
- IFLA_VF_TX_RATE, /* TX Bandwidth Allocation */
+ IFLA_VF_VLAN, /* VLAN ID and QoS */
+ IFLA_VF_TX_RATE, /* Max TX Bandwidth Allocation */
IFLA_VF_SPOOFCHK, /* Spoof Checking on/off switch */
+ IFLA_VF_LINK_STATE, /* link state enable/disable/auto switch */
+ IFLA_VF_RATE, /* Min and Max TX Bandwidth Allocation */
+ IFLA_VF_RSS_QUERY_EN, /* RSS Redirection Table and Hash Key query
+ * on/off switch
+ */
+ IFLA_VF_STATS, /* network device statistics */
+ IFLA_VF_TRUST, /* Trust VF */
+ IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */
+ IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */
+ IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */
__IFLA_VF_MAX,
};
@@ -353,16 +686,80 @@ struct ifla_vf_vlan {
__u32 qos;
};
+enum {
+ IFLA_VF_VLAN_INFO_UNSPEC,
+ IFLA_VF_VLAN_INFO, /* VLAN ID, QoS and VLAN protocol */
+ __IFLA_VF_VLAN_INFO_MAX,
+};
+
+#define IFLA_VF_VLAN_INFO_MAX (__IFLA_VF_VLAN_INFO_MAX - 1)
+#define MAX_VLAN_LIST_LEN 1
+
+struct ifla_vf_vlan_info {
+ __u32 vf;
+ __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */
+ __u32 qos;
+ __be16 vlan_proto; /* VLAN protocol either 802.1Q or 802.1ad */
+};
+
struct ifla_vf_tx_rate {
__u32 vf;
__u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */
};
+struct ifla_vf_rate {
+ __u32 vf;
+ __u32 min_tx_rate; /* Min Bandwidth in Mbps */
+ __u32 max_tx_rate; /* Max Bandwidth in Mbps */
+};
+
struct ifla_vf_spoofchk {
__u32 vf;
__u32 setting;
};
+struct ifla_vf_guid {
+ __u32 vf;
+ __u64 guid;
+};
+
+enum {
+ IFLA_VF_LINK_STATE_AUTO, /* link state of the uplink */
+ IFLA_VF_LINK_STATE_ENABLE, /* link always up */
+ IFLA_VF_LINK_STATE_DISABLE, /* link always down */
+ __IFLA_VF_LINK_STATE_MAX,
+};
+
+struct ifla_vf_link_state {
+ __u32 vf;
+ __u32 link_state;
+};
+
+struct ifla_vf_rss_query_en {
+ __u32 vf;
+ __u32 setting;
+};
+
+enum {
+ IFLA_VF_STATS_RX_PACKETS,
+ IFLA_VF_STATS_TX_PACKETS,
+ IFLA_VF_STATS_RX_BYTES,
+ IFLA_VF_STATS_TX_BYTES,
+ IFLA_VF_STATS_BROADCAST,
+ IFLA_VF_STATS_MULTICAST,
+ IFLA_VF_STATS_PAD,
+ IFLA_VF_STATS_RX_DROPPED,
+ IFLA_VF_STATS_TX_DROPPED,
+ __IFLA_VF_STATS_MAX,
+};
+
+#define IFLA_VF_STATS_MAX (__IFLA_VF_STATS_MAX - 1)
+
+struct ifla_vf_trust {
+ __u32 vf;
+ __u32 setting;
+};
+
/* VF ports management section
*
* Nested layout of set/get msg is:
@@ -453,4 +850,151 @@ enum {
#define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1)
-#endif /* _UAPI_LINUX_IF_LINK_H */
+
+/* HSR section */
+
+enum {
+ IFLA_HSR_UNSPEC,
+ IFLA_HSR_SLAVE1,
+ IFLA_HSR_SLAVE2,
+ IFLA_HSR_MULTICAST_SPEC, /* Last byte of supervision addr */
+ IFLA_HSR_SUPERVISION_ADDR, /* Supervision frame multicast addr */
+ IFLA_HSR_SEQ_NR,
+ IFLA_HSR_VERSION, /* HSR version */
+ __IFLA_HSR_MAX,
+};
+
+#define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1)
+
+/* STATS section */
+
+struct if_stats_msg {
+ __u8 family;
+ __u8 pad1;
+ __u16 pad2;
+ __u32 ifindex;
+ __u32 filter_mask;
+};
+
+/* A stats attribute can be netdev specific or a global stat.
+ * For netdev stats, lets use the prefix IFLA_STATS_LINK_*
+ */
+enum {
+ IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */
+ IFLA_STATS_LINK_64,
+ IFLA_STATS_LINK_XSTATS,
+ IFLA_STATS_LINK_XSTATS_SLAVE,
+ IFLA_STATS_LINK_OFFLOAD_XSTATS,
+ IFLA_STATS_AF_SPEC,
+ __IFLA_STATS_MAX,
+};
+
+#define IFLA_STATS_MAX (__IFLA_STATS_MAX - 1)
+
+#define IFLA_STATS_FILTER_BIT(ATTR) (1 << (ATTR - 1))
+
+/* These are embedded into IFLA_STATS_LINK_XSTATS:
+ * [IFLA_STATS_LINK_XSTATS]
+ * -> [LINK_XSTATS_TYPE_xxx]
+ * -> [rtnl link type specific attributes]
+ */
+enum {
+ LINK_XSTATS_TYPE_UNSPEC,
+ LINK_XSTATS_TYPE_BRIDGE,
+ __LINK_XSTATS_TYPE_MAX
+};
+#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1)
+
+/* These are stats embedded into IFLA_STATS_LINK_OFFLOAD_XSTATS */
+enum {
+ IFLA_OFFLOAD_XSTATS_UNSPEC,
+ IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */
+ __IFLA_OFFLOAD_XSTATS_MAX
+};
+#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1)
+
+/* XDP section */
+
+#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0)
+#define XDP_FLAGS_SKB_MODE (1U << 1)
+#define XDP_FLAGS_DRV_MODE (1U << 2)
+#define XDP_FLAGS_HW_MODE (1U << 3)
+#define XDP_FLAGS_MODES (XDP_FLAGS_SKB_MODE | \
+ XDP_FLAGS_DRV_MODE | \
+ XDP_FLAGS_HW_MODE)
+#define XDP_FLAGS_MASK (XDP_FLAGS_UPDATE_IF_NOEXIST | \
+ XDP_FLAGS_MODES)
+
+/* These are stored into IFLA_XDP_ATTACHED on dump. */
+enum {
+ XDP_ATTACHED_NONE = 0,
+ XDP_ATTACHED_DRV,
+ XDP_ATTACHED_SKB,
+ XDP_ATTACHED_HW,
+ XDP_ATTACHED_MULTI,
+};
+
+enum {
+ IFLA_XDP_UNSPEC,
+ IFLA_XDP_FD,
+ IFLA_XDP_ATTACHED,
+ IFLA_XDP_FLAGS,
+ IFLA_XDP_PROG_ID,
+ IFLA_XDP_DRV_PROG_ID,
+ IFLA_XDP_SKB_PROG_ID,
+ IFLA_XDP_HW_PROG_ID,
+ __IFLA_XDP_MAX,
+};
+
+#define IFLA_XDP_MAX (__IFLA_XDP_MAX - 1)
+
+enum {
+ IFLA_EVENT_NONE,
+ IFLA_EVENT_REBOOT, /* internal reset / reboot */
+ IFLA_EVENT_FEATURES, /* change in offload features */
+ IFLA_EVENT_BONDING_FAILOVER, /* change in active slave */
+ IFLA_EVENT_NOTIFY_PEERS, /* re-sent grat. arp/ndisc */
+ IFLA_EVENT_IGMP_RESEND, /* re-sent IGMP JOIN */
+ IFLA_EVENT_BONDING_OPTIONS, /* change in bonding options */
+};
+
+/* tun section */
+
+enum {
+ IFLA_TUN_UNSPEC,
+ IFLA_TUN_OWNER,
+ IFLA_TUN_GROUP,
+ IFLA_TUN_TYPE,
+ IFLA_TUN_PI,
+ IFLA_TUN_VNET_HDR,
+ IFLA_TUN_PERSIST,
+ IFLA_TUN_MULTI_QUEUE,
+ IFLA_TUN_NUM_QUEUES,
+ IFLA_TUN_NUM_DISABLED_QUEUES,
+ __IFLA_TUN_MAX,
+};
+
+#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1)
+
+/* rmnet section */
+
+#define RMNET_FLAGS_INGRESS_DEAGGREGATION (1U << 0)
+#define RMNET_FLAGS_INGRESS_MAP_COMMANDS (1U << 1)
+#define RMNET_FLAGS_INGRESS_MAP_CKSUMV4 (1U << 2)
+#define RMNET_FLAGS_EGRESS_MAP_CKSUMV4 (1U << 3)
+
+enum {
+ IFLA_RMNET_UNSPEC,
+ IFLA_RMNET_MUX_ID,
+ IFLA_RMNET_FLAGS,
+ __IFLA_RMNET_MAX,
+};
+
+#define IFLA_RMNET_MAX (__IFLA_RMNET_MAX - 1)
+
+struct ifla_rmnet_flags {
+ __u32 flags;
+ __u32 mask;
+};
+
+#endif /* _LINUX_IF_LINK_H */
diff --git a/include/linux-private/linux/if_macsec.h b/include/linux-private/linux/if_macsec.h
new file mode 100644
index 00000000..77439932
--- /dev/null
+++ b/include/linux-private/linux/if_macsec.h
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * include/uapi/linux/if_macsec.h - MACsec device
+ *
+ * Copyright (c) 2015 Sabrina Dubroca <sd@queasysnail.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _MACSEC_H
+#define _MACSEC_H
+
+#include <linux/types.h>
+
+#define MACSEC_GENL_NAME "macsec"
+#define MACSEC_GENL_VERSION 1
+
+#define MACSEC_MAX_KEY_LEN 128
+
+#define MACSEC_KEYID_LEN 16
+
+/* cipher IDs as per IEEE802.1AEbn-2011 */
+#define MACSEC_CIPHER_ID_GCM_AES_128 0x0080C20001000001ULL
+#define MACSEC_CIPHER_ID_GCM_AES_256 0x0080C20001000002ULL
+
+/* deprecated cipher ID for GCM-AES-128 */
+#define MACSEC_DEFAULT_CIPHER_ID 0x0080020001000001ULL
+#define MACSEC_DEFAULT_CIPHER_ALT MACSEC_CIPHER_ID_GCM_AES_128
+
+#define MACSEC_MIN_ICV_LEN 8
+#define MACSEC_MAX_ICV_LEN 32
+/* upper limit for ICV length as recommended by IEEE802.1AE-2006 */
+#define MACSEC_STD_ICV_LEN 16
+
+enum macsec_attrs {
+ MACSEC_ATTR_UNSPEC,
+ MACSEC_ATTR_IFINDEX, /* u32, ifindex of the MACsec netdevice */
+ MACSEC_ATTR_RXSC_CONFIG, /* config, nested macsec_rxsc_attrs */
+ MACSEC_ATTR_SA_CONFIG, /* config, nested macsec_sa_attrs */
+ MACSEC_ATTR_SECY, /* dump, nested macsec_secy_attrs */
+ MACSEC_ATTR_TXSA_LIST, /* dump, nested, macsec_sa_attrs for each TXSA */
+ MACSEC_ATTR_RXSC_LIST, /* dump, nested, macsec_rxsc_attrs for each RXSC */
+ MACSEC_ATTR_TXSC_STATS, /* dump, nested, macsec_txsc_stats_attr */
+ MACSEC_ATTR_SECY_STATS, /* dump, nested, macsec_secy_stats_attr */
+ __MACSEC_ATTR_END,
+ NUM_MACSEC_ATTR = __MACSEC_ATTR_END,
+ MACSEC_ATTR_MAX = __MACSEC_ATTR_END - 1,
+};
+
+enum macsec_secy_attrs {
+ MACSEC_SECY_ATTR_UNSPEC,
+ MACSEC_SECY_ATTR_SCI,
+ MACSEC_SECY_ATTR_ENCODING_SA,
+ MACSEC_SECY_ATTR_WINDOW,
+ MACSEC_SECY_ATTR_CIPHER_SUITE,
+ MACSEC_SECY_ATTR_ICV_LEN,
+ MACSEC_SECY_ATTR_PROTECT,
+ MACSEC_SECY_ATTR_REPLAY,
+ MACSEC_SECY_ATTR_OPER,
+ MACSEC_SECY_ATTR_VALIDATE,
+ MACSEC_SECY_ATTR_ENCRYPT,
+ MACSEC_SECY_ATTR_INC_SCI,
+ MACSEC_SECY_ATTR_ES,
+ MACSEC_SECY_ATTR_SCB,
+ MACSEC_SECY_ATTR_PAD,
+ __MACSEC_SECY_ATTR_END,
+ NUM_MACSEC_SECY_ATTR = __MACSEC_SECY_ATTR_END,
+ MACSEC_SECY_ATTR_MAX = __MACSEC_SECY_ATTR_END - 1,
+};
+
+enum macsec_rxsc_attrs {
+ MACSEC_RXSC_ATTR_UNSPEC,
+ MACSEC_RXSC_ATTR_SCI, /* config/dump, u64 */
+ MACSEC_RXSC_ATTR_ACTIVE, /* config/dump, u8 0..1 */
+ MACSEC_RXSC_ATTR_SA_LIST, /* dump, nested */
+ MACSEC_RXSC_ATTR_STATS, /* dump, nested, macsec_rxsc_stats_attr */
+ MACSEC_RXSC_ATTR_PAD,
+ __MACSEC_RXSC_ATTR_END,
+ NUM_MACSEC_RXSC_ATTR = __MACSEC_RXSC_ATTR_END,
+ MACSEC_RXSC_ATTR_MAX = __MACSEC_RXSC_ATTR_END - 1,
+};
+
+enum macsec_sa_attrs {
+ MACSEC_SA_ATTR_UNSPEC,
+ MACSEC_SA_ATTR_AN, /* config/dump, u8 0..3 */
+ MACSEC_SA_ATTR_ACTIVE, /* config/dump, u8 0..1 */
+ MACSEC_SA_ATTR_PN, /* config/dump, u32 */
+ MACSEC_SA_ATTR_KEY, /* config, data */
+ MACSEC_SA_ATTR_KEYID, /* config/dump, 128-bit */
+ MACSEC_SA_ATTR_STATS, /* dump, nested, macsec_sa_stats_attr */
+ MACSEC_SA_ATTR_PAD,
+ __MACSEC_SA_ATTR_END,
+ NUM_MACSEC_SA_ATTR = __MACSEC_SA_ATTR_END,
+ MACSEC_SA_ATTR_MAX = __MACSEC_SA_ATTR_END - 1,
+};
+
+enum macsec_nl_commands {
+ MACSEC_CMD_GET_TXSC,
+ MACSEC_CMD_ADD_RXSC,
+ MACSEC_CMD_DEL_RXSC,
+ MACSEC_CMD_UPD_RXSC,
+ MACSEC_CMD_ADD_TXSA,
+ MACSEC_CMD_DEL_TXSA,
+ MACSEC_CMD_UPD_TXSA,
+ MACSEC_CMD_ADD_RXSA,
+ MACSEC_CMD_DEL_RXSA,
+ MACSEC_CMD_UPD_RXSA,
+};
+
+/* u64 per-RXSC stats */
+enum macsec_rxsc_stats_attr {
+ MACSEC_RXSC_STATS_ATTR_UNSPEC,
+ MACSEC_RXSC_STATS_ATTR_IN_OCTETS_VALIDATED,
+ MACSEC_RXSC_STATS_ATTR_IN_OCTETS_DECRYPTED,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNCHECKED,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_DELAYED,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_OK,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_INVALID,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_LATE,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_VALID,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_NOT_USING_SA,
+ MACSEC_RXSC_STATS_ATTR_IN_PKTS_UNUSED_SA,
+ MACSEC_RXSC_STATS_ATTR_PAD,
+ __MACSEC_RXSC_STATS_ATTR_END,
+ NUM_MACSEC_RXSC_STATS_ATTR = __MACSEC_RXSC_STATS_ATTR_END,
+ MACSEC_RXSC_STATS_ATTR_MAX = __MACSEC_RXSC_STATS_ATTR_END - 1,
+};
+
+/* u32 per-{RX,TX}SA stats */
+enum macsec_sa_stats_attr {
+ MACSEC_SA_STATS_ATTR_UNSPEC,
+ MACSEC_SA_STATS_ATTR_IN_PKTS_OK,
+ MACSEC_SA_STATS_ATTR_IN_PKTS_INVALID,
+ MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_VALID,
+ MACSEC_SA_STATS_ATTR_IN_PKTS_NOT_USING_SA,
+ MACSEC_SA_STATS_ATTR_IN_PKTS_UNUSED_SA,
+ MACSEC_SA_STATS_ATTR_OUT_PKTS_PROTECTED,
+ MACSEC_SA_STATS_ATTR_OUT_PKTS_ENCRYPTED,
+ __MACSEC_SA_STATS_ATTR_END,
+ NUM_MACSEC_SA_STATS_ATTR = __MACSEC_SA_STATS_ATTR_END,
+ MACSEC_SA_STATS_ATTR_MAX = __MACSEC_SA_STATS_ATTR_END - 1,
+};
+
+/* u64 per-TXSC stats */
+enum macsec_txsc_stats_attr {
+ MACSEC_TXSC_STATS_ATTR_UNSPEC,
+ MACSEC_TXSC_STATS_ATTR_OUT_PKTS_PROTECTED,
+ MACSEC_TXSC_STATS_ATTR_OUT_PKTS_ENCRYPTED,
+ MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_PROTECTED,
+ MACSEC_TXSC_STATS_ATTR_OUT_OCTETS_ENCRYPTED,
+ MACSEC_TXSC_STATS_ATTR_PAD,
+ __MACSEC_TXSC_STATS_ATTR_END,
+ NUM_MACSEC_TXSC_STATS_ATTR = __MACSEC_TXSC_STATS_ATTR_END,
+ MACSEC_TXSC_STATS_ATTR_MAX = __MACSEC_TXSC_STATS_ATTR_END - 1,
+};
+
+/* u64 per-SecY stats */
+enum macsec_secy_stats_attr {
+ MACSEC_SECY_STATS_ATTR_UNSPEC,
+ MACSEC_SECY_STATS_ATTR_OUT_PKTS_UNTAGGED,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_UNTAGGED,
+ MACSEC_SECY_STATS_ATTR_OUT_PKTS_TOO_LONG,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_TAG,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_BAD_TAG,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_UNKNOWN_SCI,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_NO_SCI,
+ MACSEC_SECY_STATS_ATTR_IN_PKTS_OVERRUN,
+ MACSEC_SECY_STATS_ATTR_PAD,
+ __MACSEC_SECY_STATS_ATTR_END,
+ NUM_MACSEC_SECY_STATS_ATTR = __MACSEC_SECY_STATS_ATTR_END,
+ MACSEC_SECY_STATS_ATTR_MAX = __MACSEC_SECY_STATS_ATTR_END - 1,
+};
+
+#endif /* _MACSEC_H */
diff --git a/include/linux-private/linux/if_tunnel.h b/include/linux-private/linux/if_tunnel.h
index aee73d06..ecdc7666 100644
--- a/include/linux-private/linux/if_tunnel.h
+++ b/include/linux-private/linux/if_tunnel.h
@@ -1,7 +1,11 @@
-#ifndef _UAPI_IF_TUNNEL_H_
-#define _UAPI_IF_TUNNEL_H_
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _IF_TUNNEL_H_
+#define _IF_TUNNEL_H_
#include <linux/types.h>
+#include <linux/if.h>
+#include <linux/ip.h>
+#include <linux/in6.h>
#include <asm/byteorder.h>
@@ -24,9 +28,23 @@
#define GRE_SEQ __cpu_to_be16(0x1000)
#define GRE_STRICT __cpu_to_be16(0x0800)
#define GRE_REC __cpu_to_be16(0x0700)
-#define GRE_FLAGS __cpu_to_be16(0x00F8)
+#define GRE_ACK __cpu_to_be16(0x0080)
+#define GRE_FLAGS __cpu_to_be16(0x0078)
#define GRE_VERSION __cpu_to_be16(0x0007)
+#define GRE_IS_CSUM(f) ((f) & GRE_CSUM)
+#define GRE_IS_ROUTING(f) ((f) & GRE_ROUTING)
+#define GRE_IS_KEY(f) ((f) & GRE_KEY)
+#define GRE_IS_SEQ(f) ((f) & GRE_SEQ)
+#define GRE_IS_STRICT(f) ((f) & GRE_STRICT)
+#define GRE_IS_REC(f) ((f) & GRE_REC)
+#define GRE_IS_ACK(f) ((f) & GRE_ACK)
+
+#define GRE_VERSION_0 __cpu_to_be16(0x0000)
+#define GRE_VERSION_1 __cpu_to_be16(0x0001)
+#define GRE_PROTO_PPP __cpu_to_be16(0x880b)
+#define GRE_PPTP_KEY_MASK __cpu_to_be32(0xffff)
+
struct ip_tunnel_parm {
char name[IFNAMSIZ];
int link;
@@ -53,10 +71,27 @@ enum {
IFLA_IPTUN_6RD_RELAY_PREFIX,
IFLA_IPTUN_6RD_PREFIXLEN,
IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
+ IFLA_IPTUN_ENCAP_TYPE,
+ IFLA_IPTUN_ENCAP_FLAGS,
+ IFLA_IPTUN_ENCAP_SPORT,
+ IFLA_IPTUN_ENCAP_DPORT,
+ IFLA_IPTUN_COLLECT_METADATA,
+ IFLA_IPTUN_FWMARK,
__IFLA_IPTUN_MAX,
};
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
+enum tunnel_encap_types {
+ TUNNEL_ENCAP_NONE,
+ TUNNEL_ENCAP_FOU,
+ TUNNEL_ENCAP_GUE,
+ TUNNEL_ENCAP_MPLS,
+};
+
+#define TUNNEL_ENCAP_FLAG_CSUM (1<<0)
+#define TUNNEL_ENCAP_FLAG_CSUM6 (1<<1)
+#define TUNNEL_ENCAP_FLAG_REMCSUM (1<<2)
+
/* SIT-mode i_flags */
#define SIT_ISATAP 0x0001
@@ -94,13 +129,24 @@ enum {
IFLA_GRE_ENCAP_LIMIT,
IFLA_GRE_FLOWINFO,
IFLA_GRE_FLAGS,
+ IFLA_GRE_ENCAP_TYPE,
+ IFLA_GRE_ENCAP_FLAGS,
+ IFLA_GRE_ENCAP_SPORT,
+ IFLA_GRE_ENCAP_DPORT,
+ IFLA_GRE_COLLECT_METADATA,
+ IFLA_GRE_IGNORE_DF,
+ IFLA_GRE_FWMARK,
+ IFLA_GRE_ERSPAN_INDEX,
+ IFLA_GRE_ERSPAN_VER,
+ IFLA_GRE_ERSPAN_DIR,
+ IFLA_GRE_ERSPAN_HWID,
__IFLA_GRE_MAX,
};
#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1)
/* VTI-mode i_flags */
-#define VTI_ISVTI 0x0001
+#define VTI_ISVTI ((__be16)0x0001)
enum {
IFLA_VTI_UNSPEC,
@@ -109,8 +155,9 @@ enum {
IFLA_VTI_OKEY,
IFLA_VTI_LOCAL,
IFLA_VTI_REMOTE,
+ IFLA_VTI_FWMARK,
__IFLA_VTI_MAX,
};
#define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1)
-#endif /* _UAPI_IF_TUNNEL_H_ */
+#endif /* _IF_TUNNEL_H_ */
diff --git a/include/linux-private/linux/if_vlan.h b/include/linux-private/linux/if_vlan.h
index 67affd16..18a15dad 100644
--- a/include/linux-private/linux/if_vlan.h
+++ b/include/linux-private/linux/if_vlan.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* VLAN An implementation of 802.1Q VLAN tagging.
*
@@ -13,6 +14,7 @@
#ifndef _LINUX_IF_VLAN_H_
#define _LINUX_IF_VLAN_H_
+
/* VLAN IOCTLs are found in sockios.h */
/* Passed in vlan_ioctl_args structure to determine behaviour. */
@@ -33,6 +35,7 @@ enum vlan_flags {
VLAN_FLAG_REORDER_HDR = 0x1,
VLAN_FLAG_GVRP = 0x2,
VLAN_FLAG_LOOSE_BINDING = 0x4,
+ VLAN_FLAG_MVRP = 0x8,
};
enum vlan_name_types {
@@ -53,10 +56,10 @@ struct vlan_ioctl_args {
unsigned int skb_priority;
unsigned int name_type;
unsigned int bind_type;
- unsigned int flag; /* Matches vlan_dev_info flags */
+ unsigned int flag; /* Matches vlan_dev_priv flags */
} u;
short vlan_qos;
};
-#endif /* !(_LINUX_IF_VLAN_H_) */
+#endif /* _LINUX_IF_VLAN_H_ */
diff --git a/include/linux-private/linux/in.h b/include/linux-private/linux/in.h
new file mode 100644
index 00000000..a4f143b3
--- /dev/null
+++ b/include/linux-private/linux/in.h
@@ -0,0 +1,301 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions of the Internet Protocol.
+ *
+ * Version: @(#)in.h 1.0.1 04/21/93
+ *
+ * Authors: Original taken from the GNU Project <netinet/in.h> file.
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IN_H
+#define _LINUX_IN_H
+
+#include <linux/types.h>
+#include <linux/libc-compat.h>
+#include <linux/socket.h>
+
+#if __UAPI_DEF_IN_IPPROTO
+/* Standard well-defined IP protocols. */
+enum {
+ IPPROTO_IP = 0, /* Dummy protocol for TCP */
+#define IPPROTO_IP IPPROTO_IP
+ IPPROTO_ICMP = 1, /* Internet Control Message Protocol */
+#define IPPROTO_ICMP IPPROTO_ICMP
+ IPPROTO_IGMP = 2, /* Internet Group Management Protocol */
+#define IPPROTO_IGMP IPPROTO_IGMP
+ IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */
+#define IPPROTO_IPIP IPPROTO_IPIP
+ IPPROTO_TCP = 6, /* Transmission Control Protocol */
+#define IPPROTO_TCP IPPROTO_TCP
+ IPPROTO_EGP = 8, /* Exterior Gateway Protocol */
+#define IPPROTO_EGP IPPROTO_EGP
+ IPPROTO_PUP = 12, /* PUP protocol */
+#define IPPROTO_PUP IPPROTO_PUP
+ IPPROTO_UDP = 17, /* User Datagram Protocol */
+#define IPPROTO_UDP IPPROTO_UDP
+ IPPROTO_IDP = 22, /* XNS IDP protocol */
+#define IPPROTO_IDP IPPROTO_IDP
+ IPPROTO_TP = 29, /* SO Transport Protocol Class 4 */
+#define IPPROTO_TP IPPROTO_TP
+ IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol */
+#define IPPROTO_DCCP IPPROTO_DCCP
+ IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */
+#define IPPROTO_IPV6 IPPROTO_IPV6
+ IPPROTO_RSVP = 46, /* RSVP Protocol */
+#define IPPROTO_RSVP IPPROTO_RSVP
+ IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */
+#define IPPROTO_GRE IPPROTO_GRE
+ IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */
+#define IPPROTO_ESP IPPROTO_ESP
+ IPPROTO_AH = 51, /* Authentication Header protocol */
+#define IPPROTO_AH IPPROTO_AH
+ IPPROTO_MTP = 92, /* Multicast Transport Protocol */
+#define IPPROTO_MTP IPPROTO_MTP
+ IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */
+#define IPPROTO_BEETPH IPPROTO_BEETPH
+ IPPROTO_ENCAP = 98, /* Encapsulation Header */
+#define IPPROTO_ENCAP IPPROTO_ENCAP
+ IPPROTO_PIM = 103, /* Protocol Independent Multicast */
+#define IPPROTO_PIM IPPROTO_PIM
+ IPPROTO_COMP = 108, /* Compression Header Protocol */
+#define IPPROTO_COMP IPPROTO_COMP
+ IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */
+#define IPPROTO_SCTP IPPROTO_SCTP
+ IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */
+#define IPPROTO_UDPLITE IPPROTO_UDPLITE
+ IPPROTO_MPLS = 137, /* MPLS in IP (RFC 4023) */
+#define IPPROTO_MPLS IPPROTO_MPLS
+ IPPROTO_RAW = 255, /* Raw IP packets */
+#define IPPROTO_RAW IPPROTO_RAW
+ IPPROTO_MAX
+};
+#endif
+
+#if __UAPI_DEF_IN_ADDR
+/* Internet address. */
+struct in_addr {
+ __be32 s_addr;
+};
+#endif
+
+#define IP_TOS 1
+#define IP_TTL 2
+#define IP_HDRINCL 3
+#define IP_OPTIONS 4
+#define IP_ROUTER_ALERT 5
+#define IP_RECVOPTS 6
+#define IP_RETOPTS 7
+#define IP_PKTINFO 8
+#define IP_PKTOPTIONS 9
+#define IP_MTU_DISCOVER 10
+#define IP_RECVERR 11
+#define IP_RECVTTL 12
+#define IP_RECVTOS 13
+#define IP_MTU 14
+#define IP_FREEBIND 15
+#define IP_IPSEC_POLICY 16
+#define IP_XFRM_POLICY 17
+#define IP_PASSSEC 18
+#define IP_TRANSPARENT 19
+
+/* BSD compatibility */
+#define IP_RECVRETOPTS IP_RETOPTS
+
+/* TProxy original addresses */
+#define IP_ORIGDSTADDR 20
+#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR
+
+#define IP_MINTTL 21
+#define IP_NODEFRAG 22
+#define IP_CHECKSUM 23
+#define IP_BIND_ADDRESS_NO_PORT 24
+#define IP_RECVFRAGSIZE 25
+
+/* IP_MTU_DISCOVER values */
+#define IP_PMTUDISC_DONT 0 /* Never send DF frames */
+#define IP_PMTUDISC_WANT 1 /* Use per route hints */
+#define IP_PMTUDISC_DO 2 /* Always DF */
+#define IP_PMTUDISC_PROBE 3 /* Ignore dst pmtu */
+/* Always use interface mtu (ignores dst pmtu) but don't set DF flag.
+ * Also incoming ICMP frag_needed notifications will be ignored on
+ * this socket to prevent accepting spoofed ones.
+ */
+#define IP_PMTUDISC_INTERFACE 4
+/* weaker version of IP_PMTUDISC_INTERFACE, which allos packets to get
+ * fragmented if they exeed the interface mtu
+ */
+#define IP_PMTUDISC_OMIT 5
+
+#define IP_MULTICAST_IF 32
+#define IP_MULTICAST_TTL 33
+#define IP_MULTICAST_LOOP 34
+#define IP_ADD_MEMBERSHIP 35
+#define IP_DROP_MEMBERSHIP 36
+#define IP_UNBLOCK_SOURCE 37
+#define IP_BLOCK_SOURCE 38
+#define IP_ADD_SOURCE_MEMBERSHIP 39
+#define IP_DROP_SOURCE_MEMBERSHIP 40
+#define IP_MSFILTER 41
+#define MCAST_JOIN_GROUP 42
+#define MCAST_BLOCK_SOURCE 43
+#define MCAST_UNBLOCK_SOURCE 44
+#define MCAST_LEAVE_GROUP 45
+#define MCAST_JOIN_SOURCE_GROUP 46
+#define MCAST_LEAVE_SOURCE_GROUP 47
+#define MCAST_MSFILTER 48
+#define IP_MULTICAST_ALL 49
+#define IP_UNICAST_IF 50
+
+#define MCAST_EXCLUDE 0
+#define MCAST_INCLUDE 1
+
+/* These need to appear somewhere around here */
+#define IP_DEFAULT_MULTICAST_TTL 1
+#define IP_DEFAULT_MULTICAST_LOOP 1
+
+/* Request struct for multicast socket ops */
+
+#if __UAPI_DEF_IP_MREQ
+struct ip_mreq {
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_interface; /* local IP address of interface */
+};
+
+struct ip_mreqn {
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_address; /* local IP address of interface */
+ int imr_ifindex; /* Interface index */
+};
+
+struct ip_mreq_source {
+ __be32 imr_multiaddr;
+ __be32 imr_interface;
+ __be32 imr_sourceaddr;
+};
+
+struct ip_msfilter {
+ __be32 imsf_multiaddr;
+ __be32 imsf_interface;
+ __u32 imsf_fmode;
+ __u32 imsf_numsrc;
+ __be32 imsf_slist[1];
+};
+
+#define IP_MSFILTER_SIZE(numsrc) \
+ (sizeof(struct ip_msfilter) - sizeof(__u32) \
+ + (numsrc) * sizeof(__u32))
+
+struct group_req {
+ __u32 gr_interface; /* interface index */
+ struct __kernel_sockaddr_storage gr_group; /* group address */
+};
+
+struct group_source_req {
+ __u32 gsr_interface; /* interface index */
+ struct __kernel_sockaddr_storage gsr_group; /* group address */
+ struct __kernel_sockaddr_storage gsr_source; /* source address */
+};
+
+struct group_filter {
+ __u32 gf_interface; /* interface index */
+ struct __kernel_sockaddr_storage gf_group; /* multicast address */
+ __u32 gf_fmode; /* filter mode */
+ __u32 gf_numsrc; /* number of sources */
+ struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */
+};
+
+#define GROUP_FILTER_SIZE(numsrc) \
+ (sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \
+ + (numsrc) * sizeof(struct __kernel_sockaddr_storage))
+#endif
+
+#if __UAPI_DEF_IN_PKTINFO
+struct in_pktinfo {
+ int ipi_ifindex;
+ struct in_addr ipi_spec_dst;
+ struct in_addr ipi_addr;
+};
+#endif
+
+/* Structure describing an Internet (IP) socket address. */
+#if __UAPI_DEF_SOCKADDR_IN
+#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
+struct sockaddr_in {
+ __kernel_sa_family_t sin_family; /* Address family */
+ __be16 sin_port; /* Port number */
+ struct in_addr sin_addr; /* Internet address */
+
+ /* Pad to size of `struct sockaddr'. */
+ unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
+ sizeof(unsigned short int) - sizeof(struct in_addr)];
+};
+#define sin_zero __pad /* for BSD UNIX comp. -FvK */
+#endif
+
+#if __UAPI_DEF_IN_CLASS
+/*
+ * Definitions of the bits in an Internet address integer.
+ * On subnets, host and network parts are found according
+ * to the subnet mask, not these masks.
+ */
+#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0)
+#define IN_CLASSA_NET 0xff000000
+#define IN_CLASSA_NSHIFT 24
+#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET)
+#define IN_CLASSA_MAX 128
+
+#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000)
+#define IN_CLASSB_NET 0xffff0000
+#define IN_CLASSB_NSHIFT 16
+#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET)
+#define IN_CLASSB_MAX 65536
+
+#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000)
+#define IN_CLASSC_NET 0xffffff00
+#define IN_CLASSC_NSHIFT 8
+#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
+
+#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000)
+#define IN_MULTICAST(a) IN_CLASSD(a)
+#define IN_MULTICAST_NET 0xF0000000
+
+#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
+#define IN_BADCLASS(a) IN_EXPERIMENTAL((a))
+
+/* Address to accept any incoming messages. */
+#define INADDR_ANY ((unsigned long int) 0x00000000)
+
+/* Address to send to all hosts. */
+#define INADDR_BROADCAST ((unsigned long int) 0xffffffff)
+
+/* Address indicating an error return. */
+#define INADDR_NONE ((unsigned long int) 0xffffffff)
+
+/* Network number for local host loopback. */
+#define IN_LOOPBACKNET 127
+
+/* Address to loopback in software to local host. */
+#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */
+#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000)
+
+/* Defines for Multicast INADDR */
+#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */
+#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */
+#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */
+#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */
+#endif
+
+/* <asm/byteorder.h> contains the htonl type stuff.. */
+#include <asm/byteorder.h>
+
+
+#endif /* _LINUX_IN_H */
diff --git a/include/linux-private/linux/in6.h b/include/linux-private/linux/in6.h
new file mode 100644
index 00000000..409bb3f3
--- /dev/null
+++ b/include/linux-private/linux/in6.h
@@ -0,0 +1,298 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Types and definitions for AF_INET6
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * Sources:
+ * IPv6 Program Interfaces for BSD Systems
+ * <draft-ietf-ipngwg-bsd-api-05.txt>
+ *
+ * Advanced Sockets API for IPv6
+ * <draft-stevens-advanced-api-00.txt>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_IN6_H
+#define _LINUX_IN6_H
+
+#include <linux/types.h>
+#include <linux/libc-compat.h>
+
+/*
+ * IPv6 address structure
+ */
+
+#if __UAPI_DEF_IN6_ADDR
+struct in6_addr {
+ union {
+ __u8 u6_addr8[16];
+#if __UAPI_DEF_IN6_ADDR_ALT
+ __be16 u6_addr16[8];
+ __be32 u6_addr32[4];
+#endif
+ } in6_u;
+#define s6_addr in6_u.u6_addr8
+#if __UAPI_DEF_IN6_ADDR_ALT
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+#endif
+};
+#endif /* __UAPI_DEF_IN6_ADDR */
+
+#if __UAPI_DEF_SOCKADDR_IN6
+struct sockaddr_in6 {
+ unsigned short int sin6_family; /* AF_INET6 */
+ __be16 sin6_port; /* Transport layer port # */
+ __be32 sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ __u32 sin6_scope_id; /* scope id (new in RFC2553) */
+};
+#endif /* __UAPI_DEF_SOCKADDR_IN6 */
+
+#if __UAPI_DEF_IPV6_MREQ
+struct ipv6_mreq {
+ /* IPv6 multicast address of group */
+ struct in6_addr ipv6mr_multiaddr;
+
+ /* local IPv6 address of interface */
+ int ipv6mr_ifindex;
+};
+#endif /* __UAPI_DEF_IVP6_MREQ */
+
+#define ipv6mr_acaddr ipv6mr_multiaddr
+
+struct in6_flowlabel_req {
+ struct in6_addr flr_dst;
+ __be32 flr_label;
+ __u8 flr_action;
+ __u8 flr_share;
+ __u16 flr_flags;
+ __u16 flr_expires;
+ __u16 flr_linger;
+ __u32 __flr_pad;
+ /* Options in format of IPV6_PKTOPTIONS */
+};
+
+#define IPV6_FL_A_GET 0
+#define IPV6_FL_A_PUT 1
+#define IPV6_FL_A_RENEW 2
+
+#define IPV6_FL_F_CREATE 1
+#define IPV6_FL_F_EXCL 2
+#define IPV6_FL_F_REFLECT 4
+#define IPV6_FL_F_REMOTE 8
+
+#define IPV6_FL_S_NONE 0
+#define IPV6_FL_S_EXCL 1
+#define IPV6_FL_S_PROCESS 2
+#define IPV6_FL_S_USER 3
+#define IPV6_FL_S_ANY 255
+
+
+/*
+ * Bitmask constant declarations to help applications select out the
+ * flow label and priority fields.
+ *
+ * Note that this are in host byte order while the flowinfo field of
+ * sockaddr_in6 is in network byte order.
+ */
+
+#define IPV6_FLOWINFO_FLOWLABEL 0x000fffff
+#define IPV6_FLOWINFO_PRIORITY 0x0ff00000
+
+/* These definitions are obsolete */
+#define IPV6_PRIORITY_UNCHARACTERIZED 0x0000
+#define IPV6_PRIORITY_FILLER 0x0100
+#define IPV6_PRIORITY_UNATTENDED 0x0200
+#define IPV6_PRIORITY_RESERVED1 0x0300
+#define IPV6_PRIORITY_BULK 0x0400
+#define IPV6_PRIORITY_RESERVED2 0x0500
+#define IPV6_PRIORITY_INTERACTIVE 0x0600
+#define IPV6_PRIORITY_CONTROL 0x0700
+#define IPV6_PRIORITY_8 0x0800
+#define IPV6_PRIORITY_9 0x0900
+#define IPV6_PRIORITY_10 0x0a00
+#define IPV6_PRIORITY_11 0x0b00
+#define IPV6_PRIORITY_12 0x0c00
+#define IPV6_PRIORITY_13 0x0d00
+#define IPV6_PRIORITY_14 0x0e00
+#define IPV6_PRIORITY_15 0x0f00
+
+/*
+ * IPV6 extension headers
+ */
+#if __UAPI_DEF_IPPROTO_V6
+#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */
+#define IPPROTO_ROUTING 43 /* IPv6 routing header */
+#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */
+#define IPPROTO_ICMPV6 58 /* ICMPv6 */
+#define IPPROTO_NONE 59 /* IPv6 no next header */
+#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */
+#define IPPROTO_MH 135 /* IPv6 mobility header */
+#endif /* __UAPI_DEF_IPPROTO_V6 */
+
+/*
+ * IPv6 TLV options.
+ */
+#define IPV6_TLV_PAD1 0
+#define IPV6_TLV_PADN 1
+#define IPV6_TLV_ROUTERALERT 5
+#define IPV6_TLV_CALIPSO 7 /* RFC 5570 */
+#define IPV6_TLV_JUMBO 194
+#define IPV6_TLV_HAO 201 /* home address option */
+
+/*
+ * IPV6 socket options
+ */
+#if __UAPI_DEF_IPV6_OPTIONS
+#define IPV6_ADDRFORM 1
+#define IPV6_2292PKTINFO 2
+#define IPV6_2292HOPOPTS 3
+#define IPV6_2292DSTOPTS 4
+#define IPV6_2292RTHDR 5
+#define IPV6_2292PKTOPTIONS 6
+#define IPV6_CHECKSUM 7
+#define IPV6_2292HOPLIMIT 8
+#define IPV6_NEXTHOP 9
+#define IPV6_AUTHHDR 10 /* obsolete */
+#define IPV6_FLOWINFO 11
+
+#define IPV6_UNICAST_HOPS 16
+#define IPV6_MULTICAST_IF 17
+#define IPV6_MULTICAST_HOPS 18
+#define IPV6_MULTICAST_LOOP 19
+#define IPV6_ADD_MEMBERSHIP 20
+#define IPV6_DROP_MEMBERSHIP 21
+#define IPV6_ROUTER_ALERT 22
+#define IPV6_MTU_DISCOVER 23
+#define IPV6_MTU 24
+#define IPV6_RECVERR 25
+#define IPV6_V6ONLY 26
+#define IPV6_JOIN_ANYCAST 27
+#define IPV6_LEAVE_ANYCAST 28
+
+/* IPV6_MTU_DISCOVER values */
+#define IPV6_PMTUDISC_DONT 0
+#define IPV6_PMTUDISC_WANT 1
+#define IPV6_PMTUDISC_DO 2
+#define IPV6_PMTUDISC_PROBE 3
+/* same as IPV6_PMTUDISC_PROBE, provided for symetry with IPv4
+ * also see comments on IP_PMTUDISC_INTERFACE
+ */
+#define IPV6_PMTUDISC_INTERFACE 4
+/* weaker version of IPV6_PMTUDISC_INTERFACE, which allows packets to
+ * get fragmented if they exceed the interface mtu
+ */
+#define IPV6_PMTUDISC_OMIT 5
+
+/* Flowlabel */
+#define IPV6_FLOWLABEL_MGR 32
+#define IPV6_FLOWINFO_SEND 33
+
+#define IPV6_IPSEC_POLICY 34
+#define IPV6_XFRM_POLICY 35
+#define IPV6_HDRINCL 36
+#endif
+
+/*
+ * Multicast:
+ * Following socket options are shared between IPv4 and IPv6.
+ *
+ * MCAST_JOIN_GROUP 42
+ * MCAST_BLOCK_SOURCE 43
+ * MCAST_UNBLOCK_SOURCE 44
+ * MCAST_LEAVE_GROUP 45
+ * MCAST_JOIN_SOURCE_GROUP 46
+ * MCAST_LEAVE_SOURCE_GROUP 47
+ * MCAST_MSFILTER 48
+ */
+
+/*
+ * Advanced API (RFC3542) (1)
+ *
+ * Note: IPV6_RECVRTHDRDSTOPTS does not exist. see net/ipv6/datagram.c.
+ */
+
+#define IPV6_RECVPKTINFO 49
+#define IPV6_PKTINFO 50
+#define IPV6_RECVHOPLIMIT 51
+#define IPV6_HOPLIMIT 52
+#define IPV6_RECVHOPOPTS 53
+#define IPV6_HOPOPTS 54
+#define IPV6_RTHDRDSTOPTS 55
+#define IPV6_RECVRTHDR 56
+#define IPV6_RTHDR 57
+#define IPV6_RECVDSTOPTS 58
+#define IPV6_DSTOPTS 59
+#define IPV6_RECVPATHMTU 60
+#define IPV6_PATHMTU 61
+#define IPV6_DONTFRAG 62
+#if 0 /* not yet */
+#define IPV6_USE_MIN_MTU 63
+#endif
+
+/*
+ * Netfilter (1)
+ *
+ * Following socket options are used in ip6_tables;
+ * see include/linux/netfilter_ipv6/ip6_tables.h.
+ *
+ * IP6T_SO_SET_REPLACE / IP6T_SO_GET_INFO 64
+ * IP6T_SO_SET_ADD_COUNTERS / IP6T_SO_GET_ENTRIES 65
+ */
+
+/*
+ * Advanced API (RFC3542) (2)
+ */
+#define IPV6_RECVTCLASS 66
+#define IPV6_TCLASS 67
+
+/*
+ * Netfilter (2)
+ *
+ * Following socket options are used in ip6_tables;
+ * see include/linux/netfilter_ipv6/ip6_tables.h.
+ *
+ * IP6T_SO_GET_REVISION_MATCH 68
+ * IP6T_SO_GET_REVISION_TARGET 69
+ * IP6T_SO_ORIGINAL_DST 80
+ */
+
+#define IPV6_AUTOFLOWLABEL 70
+/* RFC5014: Source address selection */
+#define IPV6_ADDR_PREFERENCES 72
+
+#define IPV6_PREFER_SRC_TMP 0x0001
+#define IPV6_PREFER_SRC_PUBLIC 0x0002
+#define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100
+#define IPV6_PREFER_SRC_COA 0x0004
+#define IPV6_PREFER_SRC_HOME 0x0400
+#define IPV6_PREFER_SRC_CGA 0x0008
+#define IPV6_PREFER_SRC_NONCGA 0x0800
+
+/* RFC5082: Generalized Ttl Security Mechanism */
+#define IPV6_MINHOPCOUNT 73
+
+#define IPV6_ORIGDSTADDR 74
+#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR
+#define IPV6_TRANSPARENT 75
+#define IPV6_UNICAST_IF 76
+#define IPV6_RECVFRAGSIZE 77
+#define IPV6_FREEBIND 78
+
+/*
+ * Multicast Routing:
+ * see include/uapi/linux/mroute6.h.
+ *
+ * MRT6_BASE 200
+ * ...
+ * MRT6_MAX
+ */
+#endif /* _LINUX_IN6_H */
diff --git a/include/linux-private/linux/inet_diag.h b/include/linux-private/linux/inet_diag.h
new file mode 100644
index 00000000..f3bcd7ee
--- /dev/null
+++ b/include/linux-private/linux/inet_diag.h
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _INET_DIAG_H_
+#define _INET_DIAG_H_
+
+#include <linux/types.h>
+
+/* Just some random number */
+#define TCPDIAG_GETSOCK 18
+#define DCCPDIAG_GETSOCK 19
+
+#define INET_DIAG_GETSOCK_MAX 24
+
+/* Socket identity */
+struct inet_diag_sockid {
+ __be16 idiag_sport;
+ __be16 idiag_dport;
+ __be32 idiag_src[4];
+ __be32 idiag_dst[4];
+ __u32 idiag_if;
+ __u32 idiag_cookie[2];
+#define INET_DIAG_NOCOOKIE (~0U)
+};
+
+/* Request structure */
+
+struct inet_diag_req {
+ __u8 idiag_family; /* Family of addresses. */
+ __u8 idiag_src_len;
+ __u8 idiag_dst_len;
+ __u8 idiag_ext; /* Query extended information */
+
+ struct inet_diag_sockid id;
+
+ __u32 idiag_states; /* States to dump */
+ __u32 idiag_dbs; /* Tables to dump (NI) */
+};
+
+struct inet_diag_req_v2 {
+ __u8 sdiag_family;
+ __u8 sdiag_protocol;
+ __u8 idiag_ext;
+ __u8 pad;
+ __u32 idiag_states;
+ struct inet_diag_sockid id;
+};
+
+/*
+ * SOCK_RAW sockets require the underlied protocol to be
+ * additionally specified so we can use @pad member for
+ * this, but we can't rename it because userspace programs
+ * still may depend on this name. Instead lets use another
+ * structure definition as an alias for struct
+ * @inet_diag_req_v2.
+ */
+struct inet_diag_req_raw {
+ __u8 sdiag_family;
+ __u8 sdiag_protocol;
+ __u8 idiag_ext;
+ __u8 sdiag_raw_protocol;
+ __u32 idiag_states;
+ struct inet_diag_sockid id;
+};
+
+enum {
+ INET_DIAG_REQ_NONE,
+ INET_DIAG_REQ_BYTECODE,
+};
+
+#define INET_DIAG_REQ_MAX INET_DIAG_REQ_BYTECODE
+
+/* Bytecode is sequence of 4 byte commands followed by variable arguments.
+ * All the commands identified by "code" are conditional jumps forward:
+ * to offset cc+"yes" or to offset cc+"no". "yes" is supposed to be
+ * length of the command and its arguments.
+ */
+
+struct inet_diag_bc_op {
+ unsigned char code;
+ unsigned char yes;
+ unsigned short no;
+};
+
+enum {
+ INET_DIAG_BC_NOP,
+ INET_DIAG_BC_JMP,
+ INET_DIAG_BC_S_GE,
+ INET_DIAG_BC_S_LE,
+ INET_DIAG_BC_D_GE,
+ INET_DIAG_BC_D_LE,
+ INET_DIAG_BC_AUTO,
+ INET_DIAG_BC_S_COND,
+ INET_DIAG_BC_D_COND,
+ INET_DIAG_BC_DEV_COND, /* u32 ifindex */
+ INET_DIAG_BC_MARK_COND,
+ INET_DIAG_BC_S_EQ,
+ INET_DIAG_BC_D_EQ,
+};
+
+struct inet_diag_hostcond {
+ __u8 family;
+ __u8 prefix_len;
+ int port;
+ __be32 addr[0];
+};
+
+struct inet_diag_markcond {
+ __u32 mark;
+ __u32 mask;
+};
+
+/* Base info structure. It contains socket identity (addrs/ports/cookie)
+ * and, alas, the information shown by netstat. */
+struct inet_diag_msg {
+ __u8 idiag_family;
+ __u8 idiag_state;
+ __u8 idiag_timer;
+ __u8 idiag_retrans;
+
+ struct inet_diag_sockid id;
+
+ __u32 idiag_expires;
+ __u32 idiag_rqueue;
+ __u32 idiag_wqueue;
+ __u32 idiag_uid;
+ __u32 idiag_inode;
+};
+
+/* Extensions */
+
+enum {
+ INET_DIAG_NONE,
+ INET_DIAG_MEMINFO,
+ INET_DIAG_INFO,
+ INET_DIAG_VEGASINFO,
+ INET_DIAG_CONG,
+ INET_DIAG_TOS,
+ INET_DIAG_TCLASS,
+ INET_DIAG_SKMEMINFO,
+ INET_DIAG_SHUTDOWN,
+
+ /*
+ * Next extenstions cannot be requested in struct inet_diag_req_v2:
+ * its field idiag_ext has only 8 bits.
+ */
+
+ INET_DIAG_DCTCPINFO, /* request as INET_DIAG_VEGASINFO */
+ INET_DIAG_PROTOCOL, /* response attribute only */
+ INET_DIAG_SKV6ONLY,
+ INET_DIAG_LOCALS,
+ INET_DIAG_PEERS,
+ INET_DIAG_PAD,
+ INET_DIAG_MARK, /* only with CAP_NET_ADMIN */
+ INET_DIAG_BBRINFO, /* request as INET_DIAG_VEGASINFO */
+ INET_DIAG_CLASS_ID, /* request as INET_DIAG_TCLASS */
+ INET_DIAG_MD5SIG,
+ __INET_DIAG_MAX,
+};
+
+#define INET_DIAG_MAX (__INET_DIAG_MAX - 1)
+
+/* INET_DIAG_MEM */
+
+struct inet_diag_meminfo {
+ __u32 idiag_rmem;
+ __u32 idiag_wmem;
+ __u32 idiag_fmem;
+ __u32 idiag_tmem;
+};
+
+/* INET_DIAG_VEGASINFO */
+
+struct tcpvegas_info {
+ __u32 tcpv_enabled;
+ __u32 tcpv_rttcnt;
+ __u32 tcpv_rtt;
+ __u32 tcpv_minrtt;
+};
+
+/* INET_DIAG_DCTCPINFO */
+
+struct tcp_dctcp_info {
+ __u16 dctcp_enabled;
+ __u16 dctcp_ce_state;
+ __u32 dctcp_alpha;
+ __u32 dctcp_ab_ecn;
+ __u32 dctcp_ab_tot;
+};
+
+/* INET_DIAG_BBRINFO */
+
+struct tcp_bbr_info {
+ /* u64 bw: max-filtered BW (app throughput) estimate in Byte per sec: */
+ __u32 bbr_bw_lo; /* lower 32 bits of bw */
+ __u32 bbr_bw_hi; /* upper 32 bits of bw */
+ __u32 bbr_min_rtt; /* min-filtered RTT in uSec */
+ __u32 bbr_pacing_gain; /* pacing gain shifted left 8 bits */
+ __u32 bbr_cwnd_gain; /* cwnd gain shifted left 8 bits */
+};
+
+union tcp_cc_info {
+ struct tcpvegas_info vegas;
+ struct tcp_dctcp_info dctcp;
+ struct tcp_bbr_info bbr;
+};
+#endif /* _INET_DIAG_H_ */
diff --git a/include/linux-private/linux/ip.h b/include/linux-private/linux/ip.h
index 41195940..f4ecd2fa 100644
--- a/include/linux-private/linux/ip.h
+++ b/include/linux-private/linux/ip.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
/*
* INET An implementation of the TCP/IP protocol suite for the LINUX
* operating system. INET is implemented using the BSD Socket
@@ -14,8 +15,8 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#ifndef _UAPI_LINUX_IP_H
-#define _UAPI_LINUX_IP_H
+#ifndef _LINUX_IP_H
+#define _LINUX_IP_H
#include <linux/types.h>
#include <asm/byteorder.h>
@@ -164,9 +165,13 @@ enum
IPV4_DEVCONF_ROUTE_LOCALNET,
IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL,
IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL,
+ IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
+ IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
+ IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
+ IPV4_DEVCONF_BC_FORWARDING,
__IPV4_DEVCONF_MAX
};
#define IPV4_DEVCONF_MAX (__IPV4_DEVCONF_MAX - 1)
-#endif /* _UAPI_LINUX_IP_H */
+#endif /* _LINUX_IP_H */
diff --git a/include/linux-private/linux/ip_mp_alg.h b/include/linux-private/linux/ip_mp_alg.h
deleted file mode 100644
index e234e200..00000000
--- a/include/linux-private/linux/ip_mp_alg.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* ip_mp_alg.h: IPV4 multipath algorithm support, user-visible values.
- *
- * Copyright (C) 2004, 2005 Einar Lueck <elueck@de.ibm.com>
- * Copyright (C) 2005 David S. Miller <davem@davemloft.net>
- */
-
-#ifndef _LINUX_IP_MP_ALG_H
-#define _LINUX_IP_MP_ALG_H
-
-enum ip_mp_alg {
- IP_MP_ALG_NONE,
- IP_MP_ALG_RR,
- IP_MP_ALG_DRR,
- IP_MP_ALG_RANDOM,
- IP_MP_ALG_WRANDOM,
- __IP_MP_ALG_MAX
-};
-
-#define IP_MP_ALG_MAX (__IP_MP_ALG_MAX - 1)
-
-#endif /* _LINUX_IP_MP_ALG_H */
-
diff --git a/include/linux-private/linux/ipv6.h b/include/linux-private/linux/ipv6.h
index f16349df..769b4a3f 100644
--- a/include/linux-private/linux/ipv6.h
+++ b/include/linux-private/linux/ipv6.h
@@ -1,6 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _IPV6_H
#define _IPV6_H
+#include <linux/libc-compat.h>
+#include <linux/types.h>
+#include <linux/in6.h>
#include <asm/byteorder.h>
/* The latest drafts declared increase in minimal mtu up to 1280. */
@@ -13,10 +17,30 @@
* *under construction*
*/
+#if __UAPI_DEF_IN6_PKTINFO
+struct in6_pktinfo {
+ struct in6_addr ipi6_addr;
+ int ipi6_ifindex;
+};
+#endif
+
+#if __UAPI_DEF_IP6_MTUINFO
+struct ip6_mtuinfo {
+ struct sockaddr_in6 ip6m_addr;
+ __u32 ip6m_mtu;
+};
+#endif
+
+struct in6_ifreq {
+ struct in6_addr ifr6_addr;
+ __u32 ifr6_prefixlen;
+ int ifr6_ifindex;
+};
#define IPV6_SRCRT_STRICT 0x01 /* Deprecated; will be removed */
#define IPV6_SRCRT_TYPE_0 0 /* Deprecated; will be removed */
#define IPV6_SRCRT_TYPE_2 2 /* IPv6 type 2 Routing Header */
+#define IPV6_SRCRT_TYPE_4 4 /* Segment Routing with IPv6 */
/*
* routing header
@@ -45,6 +69,8 @@ struct ipv6_opt_hdr {
#define ipv6_destopt_hdr ipv6_opt_hdr
#define ipv6_hopopt_hdr ipv6_opt_hdr
+/* Router Alert option values (RFC2711) */
+#define IPV6_OPT_ROUTERALERT_MLD 0x0000 /* MLD(RFC2710) */
/*
* routing header type 0 (used in cmsghdr struct)
@@ -139,6 +165,28 @@ enum {
DEVCONF_DISABLE_IPV6,
DEVCONF_ACCEPT_DAD,
DEVCONF_FORCE_TLLAO,
+ DEVCONF_NDISC_NOTIFY,
+ DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL,
+ DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL,
+ DEVCONF_SUPPRESS_FRAG_NDISC,
+ DEVCONF_ACCEPT_RA_FROM_LOCAL,
+ DEVCONF_USE_OPTIMISTIC,
+ DEVCONF_ACCEPT_RA_MTU,
+ DEVCONF_STABLE_SECRET,
+ DEVCONF_USE_OIF_ADDRS_ONLY,
+ DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT,
+ DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN,
+ DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
+ DEVCONF_DROP_UNSOLICITED_NA,
+ DEVCONF_KEEP_ADDR_ON_DOWN,
+ DEVCONF_RTR_SOLICIT_MAX_INTERVAL,
+ DEVCONF_SEG6_ENABLED,
+ DEVCONF_SEG6_REQUIRE_HMAC,
+ DEVCONF_ENHANCED_DAD,
+ DEVCONF_ADDR_GEN_MODE,
+ DEVCONF_DISABLE_POLICY,
+ DEVCONF_ACCEPT_RA_RT_INFO_MIN_PLEN,
+ DEVCONF_NDISC_TCLASS,
DEVCONF_MAX
};
diff --git a/include/linux-private/linux/libc-compat.h b/include/linux-private/linux/libc-compat.h
new file mode 100644
index 00000000..a1599911
--- /dev/null
+++ b/include/linux-private/linux/libc-compat.h
@@ -0,0 +1,267 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Compatibility interface for userspace libc header coordination:
+ *
+ * Define compatibility macros that are used to control the inclusion or
+ * exclusion of UAPI structures and definitions in coordination with another
+ * userspace C library.
+ *
+ * This header is intended to solve the problem of UAPI definitions that
+ * conflict with userspace definitions. If a UAPI header has such conflicting
+ * definitions then the solution is as follows:
+ *
+ * * Synchronize the UAPI header and the libc headers so either one can be
+ * used and such that the ABI is preserved. If this is not possible then
+ * no simple compatibility interface exists (you need to write translating
+ * wrappers and rename things) and you can't use this interface.
+ *
+ * Then follow this process:
+ *
+ * (a) Include libc-compat.h in the UAPI header.
+ * e.g. #include <linux/libc-compat.h>
+ * This include must be as early as possible.
+ *
+ * (b) In libc-compat.h add enough code to detect that the comflicting
+ * userspace libc header has been included first.
+ *
+ * (c) If the userspace libc header has been included first define a set of
+ * guard macros of the form __UAPI_DEF_FOO and set their values to 1, else
+ * set their values to 0.
+ *
+ * (d) Back in the UAPI header with the conflicting definitions, guard the
+ * definitions with:
+ * #if __UAPI_DEF_FOO
+ * ...
+ * #endif
+ *
+ * This fixes the situation where the linux headers are included *after* the
+ * libc headers. To fix the problem with the inclusion in the other order the
+ * userspace libc headers must be fixed like this:
+ *
+ * * For all definitions that conflict with kernel definitions wrap those
+ * defines in the following:
+ * #if !__UAPI_DEF_FOO
+ * ...
+ * #endif
+ *
+ * This prevents the redefinition of a construct already defined by the kernel.
+ */
+#ifndef _LIBC_COMPAT_H
+#define _LIBC_COMPAT_H
+
+/* We have included glibc headers... */
+#if defined(__GLIBC__)
+
+/* Coordinate with glibc net/if.h header. */
+#if defined(_NET_IF_H) && defined(__USE_MISC)
+
+/* GLIBC headers included first so don't define anything
+ * that would already be defined. */
+
+#define __UAPI_DEF_IF_IFCONF 0
+#define __UAPI_DEF_IF_IFMAP 0
+#define __UAPI_DEF_IF_IFNAMSIZ 0
+#define __UAPI_DEF_IF_IFREQ 0
+/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0
+/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
+#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
+
+#else /* _NET_IF_H */
+
+/* Linux headers included first, and we must define everything
+ * we need. The expectation is that glibc will check the
+ * __UAPI_DEF_* defines and adjust appropriately. */
+
+#define __UAPI_DEF_IF_IFCONF 1
+#define __UAPI_DEF_IF_IFMAP 1
+#define __UAPI_DEF_IF_IFNAMSIZ 1
+#define __UAPI_DEF_IF_IFREQ 1
+/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1
+/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+
+#endif /* _NET_IF_H */
+
+/* Coordinate with glibc netinet/in.h header. */
+#if defined(_NETINET_IN_H)
+
+/* GLIBC headers included first so don't define anything
+ * that would already be defined. */
+#define __UAPI_DEF_IN_ADDR 0
+#define __UAPI_DEF_IN_IPPROTO 0
+#define __UAPI_DEF_IN_PKTINFO 0
+#define __UAPI_DEF_IP_MREQ 0
+#define __UAPI_DEF_SOCKADDR_IN 0
+#define __UAPI_DEF_IN_CLASS 0
+
+#define __UAPI_DEF_IN6_ADDR 0
+/* The exception is the in6_addr macros which must be defined
+ * if the glibc code didn't define them. This guard matches
+ * the guard in glibc/inet/netinet/in.h which defines the
+ * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */
+#if defined(__USE_MISC) || defined (__USE_GNU)
+#define __UAPI_DEF_IN6_ADDR_ALT 0
+#else
+#define __UAPI_DEF_IN6_ADDR_ALT 1
+#endif
+#define __UAPI_DEF_SOCKADDR_IN6 0
+#define __UAPI_DEF_IPV6_MREQ 0
+#define __UAPI_DEF_IPPROTO_V6 0
+#define __UAPI_DEF_IPV6_OPTIONS 0
+#define __UAPI_DEF_IN6_PKTINFO 0
+#define __UAPI_DEF_IP6_MTUINFO 0
+
+#else
+
+/* Linux headers included first, and we must define everything
+ * we need. The expectation is that glibc will check the
+ * __UAPI_DEF_* defines and adjust appropriately. */
+#define __UAPI_DEF_IN_ADDR 1
+#define __UAPI_DEF_IN_IPPROTO 1
+#define __UAPI_DEF_IN_PKTINFO 1
+#define __UAPI_DEF_IP_MREQ 1
+#define __UAPI_DEF_SOCKADDR_IN 1
+#define __UAPI_DEF_IN_CLASS 1
+
+#define __UAPI_DEF_IN6_ADDR 1
+/* We unconditionally define the in6_addr macros and glibc must
+ * coordinate. */
+#define __UAPI_DEF_IN6_ADDR_ALT 1
+#define __UAPI_DEF_SOCKADDR_IN6 1
+#define __UAPI_DEF_IPV6_MREQ 1
+#define __UAPI_DEF_IPPROTO_V6 1
+#define __UAPI_DEF_IPV6_OPTIONS 1
+#define __UAPI_DEF_IN6_PKTINFO 1
+#define __UAPI_DEF_IP6_MTUINFO 1
+
+#endif /* _NETINET_IN_H */
+
+/* Coordinate with glibc netipx/ipx.h header. */
+#if defined(__NETIPX_IPX_H)
+
+#define __UAPI_DEF_SOCKADDR_IPX 0
+#define __UAPI_DEF_IPX_ROUTE_DEFINITION 0
+#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 0
+#define __UAPI_DEF_IPX_CONFIG_DATA 0
+#define __UAPI_DEF_IPX_ROUTE_DEF 0
+
+#else /* defined(__NETIPX_IPX_H) */
+
+#define __UAPI_DEF_SOCKADDR_IPX 1
+#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1
+#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1
+#define __UAPI_DEF_IPX_CONFIG_DATA 1
+#define __UAPI_DEF_IPX_ROUTE_DEF 1
+
+#endif /* defined(__NETIPX_IPX_H) */
+
+/* Definitions for xattr.h */
+#if defined(_SYS_XATTR_H)
+#define __UAPI_DEF_XATTR 0
+#else
+#define __UAPI_DEF_XATTR 1
+#endif
+
+/* If we did not see any headers from any supported C libraries,
+ * or we are being included in the kernel, then define everything
+ * that we need. Check for previous __UAPI_* definitions to give
+ * unsupported C libraries a way to opt out of any kernel definition. */
+#else /* !defined(__GLIBC__) */
+
+/* Definitions for if.h */
+#ifndef __UAPI_DEF_IF_IFCONF
+#define __UAPI_DEF_IF_IFCONF 1
+#endif
+#ifndef __UAPI_DEF_IF_IFMAP
+#define __UAPI_DEF_IF_IFMAP 1
+#endif
+#ifndef __UAPI_DEF_IF_IFNAMSIZ
+#define __UAPI_DEF_IF_IFNAMSIZ 1
+#endif
+#ifndef __UAPI_DEF_IF_IFREQ
+#define __UAPI_DEF_IF_IFREQ 1
+#endif
+/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */
+#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1
+#endif
+/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
+#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
+#endif
+
+/* Definitions for in.h */
+#ifndef __UAPI_DEF_IN_ADDR
+#define __UAPI_DEF_IN_ADDR 1
+#endif
+#ifndef __UAPI_DEF_IN_IPPROTO
+#define __UAPI_DEF_IN_IPPROTO 1
+#endif
+#ifndef __UAPI_DEF_IN_PKTINFO
+#define __UAPI_DEF_IN_PKTINFO 1
+#endif
+#ifndef __UAPI_DEF_IP_MREQ
+#define __UAPI_DEF_IP_MREQ 1
+#endif
+#ifndef __UAPI_DEF_SOCKADDR_IN
+#define __UAPI_DEF_SOCKADDR_IN 1
+#endif
+#ifndef __UAPI_DEF_IN_CLASS
+#define __UAPI_DEF_IN_CLASS 1
+#endif
+
+/* Definitions for in6.h */
+#ifndef __UAPI_DEF_IN6_ADDR
+#define __UAPI_DEF_IN6_ADDR 1
+#endif
+#ifndef __UAPI_DEF_IN6_ADDR_ALT
+#define __UAPI_DEF_IN6_ADDR_ALT 1
+#endif
+#ifndef __UAPI_DEF_SOCKADDR_IN6
+#define __UAPI_DEF_SOCKADDR_IN6 1
+#endif
+#ifndef __UAPI_DEF_IPV6_MREQ
+#define __UAPI_DEF_IPV6_MREQ 1
+#endif
+#ifndef __UAPI_DEF_IPPROTO_V6
+#define __UAPI_DEF_IPPROTO_V6 1
+#endif
+#ifndef __UAPI_DEF_IPV6_OPTIONS
+#define __UAPI_DEF_IPV6_OPTIONS 1
+#endif
+#ifndef __UAPI_DEF_IN6_PKTINFO
+#define __UAPI_DEF_IN6_PKTINFO 1
+#endif
+#ifndef __UAPI_DEF_IP6_MTUINFO
+#define __UAPI_DEF_IP6_MTUINFO 1
+#endif
+
+/* Definitions for ipx.h */
+#ifndef __UAPI_DEF_SOCKADDR_IPX
+#define __UAPI_DEF_SOCKADDR_IPX 1
+#endif
+#ifndef __UAPI_DEF_IPX_ROUTE_DEFINITION
+#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1
+#endif
+#ifndef __UAPI_DEF_IPX_INTERFACE_DEFINITION
+#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1
+#endif
+#ifndef __UAPI_DEF_IPX_CONFIG_DATA
+#define __UAPI_DEF_IPX_CONFIG_DATA 1
+#endif
+#ifndef __UAPI_DEF_IPX_ROUTE_DEF
+#define __UAPI_DEF_IPX_ROUTE_DEF 1
+#endif
+
+/* Definitions for xattr.h */
+#ifndef __UAPI_DEF_XATTR
+#define __UAPI_DEF_XATTR 1
+#endif
+
+#endif /* __GLIBC__ */
+
+#endif /* _LIBC_COMPAT_H */
diff --git a/include/linux-private/linux/lwtunnel.h b/include/linux-private/linux/lwtunnel.h
new file mode 100644
index 00000000..3f3fe6f3
--- /dev/null
+++ b/include/linux-private/linux/lwtunnel.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LWTUNNEL_H_
+#define _LWTUNNEL_H_
+
+#include <linux/types.h>
+
+enum lwtunnel_encap_types {
+ LWTUNNEL_ENCAP_NONE,
+ LWTUNNEL_ENCAP_MPLS,
+ LWTUNNEL_ENCAP_IP,
+ LWTUNNEL_ENCAP_ILA,
+ LWTUNNEL_ENCAP_IP6,
+ LWTUNNEL_ENCAP_SEG6,
+ LWTUNNEL_ENCAP_BPF,
+ LWTUNNEL_ENCAP_SEG6_LOCAL,
+ __LWTUNNEL_ENCAP_MAX,
+};
+
+#define LWTUNNEL_ENCAP_MAX (__LWTUNNEL_ENCAP_MAX - 1)
+
+enum lwtunnel_ip_t {
+ LWTUNNEL_IP_UNSPEC,
+ LWTUNNEL_IP_ID,
+ LWTUNNEL_IP_DST,
+ LWTUNNEL_IP_SRC,
+ LWTUNNEL_IP_TTL,
+ LWTUNNEL_IP_TOS,
+ LWTUNNEL_IP_FLAGS,
+ LWTUNNEL_IP_PAD,
+ __LWTUNNEL_IP_MAX,
+};
+
+#define LWTUNNEL_IP_MAX (__LWTUNNEL_IP_MAX - 1)
+
+enum lwtunnel_ip6_t {
+ LWTUNNEL_IP6_UNSPEC,
+ LWTUNNEL_IP6_ID,
+ LWTUNNEL_IP6_DST,
+ LWTUNNEL_IP6_SRC,
+ LWTUNNEL_IP6_HOPLIMIT,
+ LWTUNNEL_IP6_TC,
+ LWTUNNEL_IP6_FLAGS,
+ LWTUNNEL_IP6_PAD,
+ __LWTUNNEL_IP6_MAX,
+};
+
+#define LWTUNNEL_IP6_MAX (__LWTUNNEL_IP6_MAX - 1)
+
+enum {
+ LWT_BPF_PROG_UNSPEC,
+ LWT_BPF_PROG_FD,
+ LWT_BPF_PROG_NAME,
+ __LWT_BPF_PROG_MAX,
+};
+
+#define LWT_BPF_PROG_MAX (__LWT_BPF_PROG_MAX - 1)
+
+enum {
+ LWT_BPF_UNSPEC,
+ LWT_BPF_IN,
+ LWT_BPF_OUT,
+ LWT_BPF_XMIT,
+ LWT_BPF_XMIT_HEADROOM,
+ __LWT_BPF_MAX,
+};
+
+#define LWT_BPF_MAX (__LWT_BPF_MAX - 1)
+
+#define LWT_BPF_MAX_HEADROOM 256
+
+#endif /* _LWTUNNEL_H_ */
diff --git a/include/linux-private/linux/mpls.h b/include/linux-private/linux/mpls.h
new file mode 100644
index 00000000..9effbf99
--- /dev/null
+++ b/include/linux-private/linux/mpls.h
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _MPLS_H
+#define _MPLS_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/* Reference: RFC 5462, RFC 3032
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Label | TC |S| TTL |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * Label: Label Value, 20 bits
+ * TC: Traffic Class field, 3 bits
+ * S: Bottom of Stack, 1 bit
+ * TTL: Time to Live, 8 bits
+ */
+
+struct mpls_label {
+ __be32 entry;
+};
+
+#define MPLS_LS_LABEL_MASK 0xFFFFF000
+#define MPLS_LS_LABEL_SHIFT 12
+#define MPLS_LS_TC_MASK 0x00000E00
+#define MPLS_LS_TC_SHIFT 9
+#define MPLS_LS_S_MASK 0x00000100
+#define MPLS_LS_S_SHIFT 8
+#define MPLS_LS_TTL_MASK 0x000000FF
+#define MPLS_LS_TTL_SHIFT 0
+
+/* Reserved labels */
+#define MPLS_LABEL_IPV4NULL 0 /* RFC3032 */
+#define MPLS_LABEL_RTALERT 1 /* RFC3032 */
+#define MPLS_LABEL_IPV6NULL 2 /* RFC3032 */
+#define MPLS_LABEL_IMPLNULL 3 /* RFC3032 */
+#define MPLS_LABEL_ENTROPY 7 /* RFC6790 */
+#define MPLS_LABEL_GAL 13 /* RFC5586 */
+#define MPLS_LABEL_OAMALERT 14 /* RFC3429 */
+#define MPLS_LABEL_EXTENSION 15 /* RFC7274 */
+
+#define MPLS_LABEL_FIRST_UNRESERVED 16 /* RFC3032 */
+
+/* These are embedded into IFLA_STATS_AF_SPEC:
+ * [IFLA_STATS_AF_SPEC]
+ * -> [AF_MPLS]
+ * -> [MPLS_STATS_xxx]
+ *
+ * Attributes:
+ * [MPLS_STATS_LINK] = {
+ * struct mpls_link_stats
+ * }
+ */
+enum {
+ MPLS_STATS_UNSPEC, /* also used as 64bit pad attribute */
+ MPLS_STATS_LINK,
+ __MPLS_STATS_MAX,
+};
+
+#define MPLS_STATS_MAX (__MPLS_STATS_MAX - 1)
+
+struct mpls_link_stats {
+ __u64 rx_packets; /* total packets received */
+ __u64 tx_packets; /* total packets transmitted */
+ __u64 rx_bytes; /* total bytes received */
+ __u64 tx_bytes; /* total bytes transmitted */
+ __u64 rx_errors; /* bad packets received */
+ __u64 tx_errors; /* packet transmit problems */
+ __u64 rx_dropped; /* packet dropped on receive */
+ __u64 tx_dropped; /* packet dropped on transmit */
+ __u64 rx_noroute; /* no route for packet dest */
+};
+
+#endif /* _MPLS_H */
diff --git a/include/linux-private/linux/mpls_iptunnel.h b/include/linux-private/linux/mpls_iptunnel.h
new file mode 100644
index 00000000..2c69b7dd
--- /dev/null
+++ b/include/linux-private/linux/mpls_iptunnel.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * mpls tunnel api
+ *
+ * Authors:
+ * Roopa Prabhu <roopa@cumulusnetworks.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_MPLS_IPTUNNEL_H
+#define _LINUX_MPLS_IPTUNNEL_H
+
+/* MPLS tunnel attributes
+ * [RTA_ENCAP] = {
+ * [MPLS_IPTUNNEL_DST]
+ * [MPLS_IPTUNNEL_TTL]
+ * }
+ */
+enum {
+ MPLS_IPTUNNEL_UNSPEC,
+ MPLS_IPTUNNEL_DST,
+ MPLS_IPTUNNEL_TTL,
+ __MPLS_IPTUNNEL_MAX,
+};
+#define MPLS_IPTUNNEL_MAX (__MPLS_IPTUNNEL_MAX - 1)
+
+#endif /* _LINUX_MPLS_IPTUNNEL_H */
diff --git a/include/linux-private/linux/neighbour.h b/include/linux-private/linux/neighbour.h
index a7003b7a..904db614 100644
--- a/include/linux-private/linux/neighbour.h
+++ b/include/linux-private/linux/neighbour.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_NEIGHBOUR_H
#define __LINUX_NEIGHBOUR_H
@@ -20,6 +21,13 @@ enum {
NDA_LLADDR,
NDA_CACHEINFO,
NDA_PROBES,
+ NDA_VLAN,
+ NDA_PORT,
+ NDA_VNI,
+ NDA_IFINDEX,
+ NDA_MASTER,
+ NDA_LINK_NETNSID,
+ NDA_SRC_VNI,
__NDA_MAX
};
@@ -30,7 +38,11 @@ enum {
*/
#define NTF_USE 0x01
+#define NTF_SELF 0x02
+#define NTF_MASTER 0x04
#define NTF_PROXY 0x08 /* == ATF_PUBL */
+#define NTF_EXT_LEARNED 0x10
+#define NTF_OFFLOADED 0x20
#define NTF_ROUTER 0x80
/*
@@ -51,7 +63,7 @@ enum {
/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change
and make no address resolution or NUD.
- NUD_PERMANENT is also cannot be deleted by garbage collectors.
+ NUD_PERMANENT also cannot be deleted by garbage collectors.
*/
struct nda_cacheinfo {
@@ -97,6 +109,7 @@ struct ndt_stats {
__u64 ndts_rcv_probes_ucast;
__u64 ndts_periodic_gc_runs;
__u64 ndts_forced_gc_runs;
+ __u64 ndts_table_fulls;
};
enum {
@@ -116,6 +129,9 @@ enum {
NDTPA_PROXY_DELAY, /* u64, msecs */
NDTPA_PROXY_QLEN, /* u32 */
NDTPA_LOCKTIME, /* u64, msecs */
+ NDTPA_QUEUE_LENBYTES, /* u32 */
+ NDTPA_MCAST_REPROBES, /* u32 */
+ NDTPA_PAD,
__NDTPA_MAX
};
#define NDTPA_MAX (__NDTPA_MAX - 1)
@@ -148,6 +164,7 @@ enum {
NDTA_PARMS, /* nested TLV NDTPA_* */
NDTA_STATS, /* struct ndt_stats, read-only */
NDTA_GC_INTERVAL, /* u64, msecs */
+ NDTA_PAD,
__NDTA_MAX
};
#define NDTA_MAX (__NDTA_MAX - 1)
diff --git a/include/linux-private/linux/netconf.h b/include/linux-private/linux/netconf.h
new file mode 100644
index 00000000..229e8851
--- /dev/null
+++ b/include/linux-private/linux/netconf.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_NETCONF_H_
+#define _LINUX_NETCONF_H_
+
+#include <linux/types.h>
+#include <linux/netlink.h>
+
+struct netconfmsg {
+ __u8 ncm_family;
+};
+
+enum {
+ NETCONFA_UNSPEC,
+ NETCONFA_IFINDEX,
+ NETCONFA_FORWARDING,
+ NETCONFA_RP_FILTER,
+ NETCONFA_MC_FORWARDING,
+ NETCONFA_PROXY_NEIGH,
+ NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN,
+ NETCONFA_INPUT,
+ NETCONFA_BC_FORWARDING,
+ __NETCONFA_MAX
+};
+#define NETCONFA_MAX (__NETCONFA_MAX - 1)
+#define NETCONFA_ALL -1
+
+#define NETCONFA_IFINDEX_ALL -1
+#define NETCONFA_IFINDEX_DEFAULT -2
+
+#endif /* _LINUX_NETCONF_H_ */
diff --git a/include/linux-private/linux/netfilter.h b/include/linux-private/linux/netfilter.h
index 79998855..36378a0a 100644
--- a/include/linux-private/linux/netfilter.h
+++ b/include/linux-private/linux/netfilter.h
@@ -1,32 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_NETFILTER_H
#define __LINUX_NETFILTER_H
#include <linux/types.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+
/* Responses from hook functions. */
#define NF_DROP 0
#define NF_ACCEPT 1
#define NF_STOLEN 2
#define NF_QUEUE 3
#define NF_REPEAT 4
-#define NF_STOP 5
+#define NF_STOP 5 /* Deprecated, for userspace nf_queue compatibility. */
#define NF_MAX_VERDICT NF_STOP
/* we overload the higher bits for encoding auxiliary data such as the queue
- * number. Not nice, but better than additional function arguments. */
-#define NF_VERDICT_MASK 0x0000ffff
-#define NF_VERDICT_BITS 16
+ * number or errno values. Not nice, but better than additional function
+ * arguments. */
+#define NF_VERDICT_MASK 0x000000ff
+/* extra verdict flags have mask 0x0000ff00 */
+#define NF_VERDICT_FLAG_QUEUE_BYPASS 0x00008000
+
+/* queue number (NF_QUEUE) or errno (NF_DROP) */
#define NF_VERDICT_QMASK 0xffff0000
#define NF_VERDICT_QBITS 16
-#define NF_QUEUE_NR(x) ((((x) << NF_VERDICT_BITS) & NF_VERDICT_QMASK) | NF_QUEUE)
+#define NF_QUEUE_NR(x) ((((x) << 16) & NF_VERDICT_QMASK) | NF_QUEUE)
+
+#define NF_DROP_ERR(x) (((-x) << 16) | NF_DROP)
+/* only for userspace compatibility */
/* Generic cache responses from hook functions.
<= 0x2000 is used for protocol-flags. */
#define NFC_UNKNOWN 0x4000
#define NFC_ALTERED 0x8000
+/* NF_VERDICT_BITS should be 8 now, but userspace might break if this changes */
+#define NF_VERDICT_BITS 16
+
enum nf_inet_hooks {
NF_INET_PRE_ROUTING,
NF_INET_LOCAL_IN,
@@ -36,10 +50,17 @@ enum nf_inet_hooks {
NF_INET_NUMHOOKS
};
+enum nf_dev_hooks {
+ NF_NETDEV_INGRESS,
+ NF_NETDEV_NUMHOOKS
+};
+
enum {
NFPROTO_UNSPEC = 0,
+ NFPROTO_INET = 1,
NFPROTO_IPV4 = 2,
NFPROTO_ARP = 3,
+ NFPROTO_NETDEV = 5,
NFPROTO_BRIDGE = 7,
NFPROTO_IPV6 = 10,
NFPROTO_DECNET = 12,
@@ -54,4 +75,4 @@ union nf_inet_addr {
struct in6_addr in6;
};
-#endif /*__LINUX_NETFILTER_H*/
+#endif /* __LINUX_NETFILTER_H */
diff --git a/include/linux-private/linux/netfilter/nf_conntrack_common.h b/include/linux-private/linux/netfilter/nf_conntrack_common.h
index 1644cdd8..dc374c9f 100644
--- a/include/linux-private/linux/netfilter/nf_conntrack_common.h
+++ b/include/linux-private/linux/netfilter/nf_conntrack_common.h
@@ -1,5 +1,6 @@
-#ifndef _UAPI_NF_CONNTRACK_COMMON_H
-#define _UAPI_NF_CONNTRACK_COMMON_H
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _NF_CONNTRACK_COMMON_H
+#define _NF_CONNTRACK_COMMON_H
/* Connection state tracking for netfilter. This is separated from,
but required by, the NAT layer; it can also be used by an iptables
extension. */
@@ -20,11 +21,19 @@ enum ip_conntrack_info {
IP_CT_ESTABLISHED_REPLY = IP_CT_ESTABLISHED + IP_CT_IS_REPLY,
IP_CT_RELATED_REPLY = IP_CT_RELATED + IP_CT_IS_REPLY,
- IP_CT_NEW_REPLY = IP_CT_NEW + IP_CT_IS_REPLY,
- /* Number of distinct IP_CT types (no NEW in reply dirn). */
- IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1
+ /* No NEW in reply direction. */
+
+ /* Number of distinct IP_CT types. */
+ IP_CT_NUMBER,
+
+ /* only for userspace compatibility */
+ IP_CT_NEW_REPLY = IP_CT_NUMBER,
};
+#define NF_CT_STATE_INVALID_BIT (1 << 0)
+#define NF_CT_STATE_BIT(ctinfo) (1 << ((ctinfo) % IP_CT_IS_REPLY + 1))
+#define NF_CT_STATE_UNTRACKED_BIT (1 << 6)
+
/* Bitset representing status of connection. */
enum ip_conntrack_status {
/* It's an expected connection: bit 0 set. This bit never changed */
@@ -80,13 +89,26 @@ enum ip_conntrack_status {
IPS_TEMPLATE_BIT = 11,
IPS_TEMPLATE = (1 << IPS_TEMPLATE_BIT),
- /* Conntrack is a fake untracked entry */
+ /* Conntrack is a fake untracked entry. Obsolete and not used anymore */
IPS_UNTRACKED_BIT = 12,
IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT),
/* Conntrack got a helper explicitly attached via CT target. */
IPS_HELPER_BIT = 13,
IPS_HELPER = (1 << IPS_HELPER_BIT),
+
+ /* Conntrack has been offloaded to flow table. */
+ IPS_OFFLOAD_BIT = 14,
+ IPS_OFFLOAD = (1 << IPS_OFFLOAD_BIT),
+
+ /* Be careful here, modifying these bits can make things messy,
+ * so don't let users modify them directly.
+ */
+ IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK |
+ IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING |
+ IPS_SEQ_ADJUST | IPS_TEMPLATE | IPS_OFFLOAD),
+
+ __IPS_MAX_BIT = 15,
};
/* Connection tracking event types */
@@ -99,8 +121,11 @@ enum ip_conntrack_events {
IPCT_PROTOINFO, /* protocol information has changed */
IPCT_HELPER, /* new helper has been set */
IPCT_MARK, /* new mark has been set */
- IPCT_NATSEQADJ, /* NAT is doing sequence adjustment */
+ IPCT_SEQADJ, /* sequence adjustment has changed */
+ IPCT_NATSEQADJ = IPCT_SEQADJ,
IPCT_SECMARK, /* new security mark has been set */
+ IPCT_LABEL, /* new connlabel has been set */
+ IPCT_SYNPROXY, /* synproxy has been set */
};
enum ip_conntrack_expect_events {
@@ -114,4 +139,4 @@ enum ip_conntrack_expect_events {
#define NF_CT_EXPECT_USERSPACE 0x4
-#endif /* _UAPI_NF_CONNTRACK_COMMON_H */
+#endif /* _NF_CONNTRACK_COMMON_H */
diff --git a/include/linux-private/linux/netfilter/nfnetlink.h b/include/linux-private/linux/netfilter/nfnetlink.h
index 1fe29727..a89f3a56 100644
--- a/include/linux-private/linux/netfilter/nfnetlink.h
+++ b/include/linux-private/linux/netfilter/nfnetlink.h
@@ -1,17 +1,8 @@
-#ifndef _UAPI_NFNETLINK_H
-#define _UAPI_NFNETLINK_H
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _NFNETLINK_H
+#define _NFNETLINK_H
#include <linux/types.h>
-
-#ifndef __KERNEL__
-/* nfnetlink groups: Up to 32 maximum - backwards compatibility for userspace */
-#define NF_NETLINK_CONNTRACK_NEW 0x00000001
-#define NF_NETLINK_CONNTRACK_UPDATE 0x00000002
-#define NF_NETLINK_CONNTRACK_DESTROY 0x00000004
-#define NF_NETLINK_CONNTRACK_EXP_NEW 0x00000008
-#define NF_NETLINK_CONNTRACK_EXP_UPDATE 0x00000010
-#define NF_NETLINK_CONNTRACK_EXP_DESTROY 0x00000020
-#define NF_NETLINK_ACCT_QUOTA 0x00000040
-#endif
+#include <linux/netfilter/nfnetlink_compat.h>
enum nfnetlink_groups {
NFNLGRP_NONE,
@@ -29,9 +20,11 @@ enum nfnetlink_groups {
NFNLGRP_CONNTRACK_EXP_DESTROY,
#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY
NFNLGRP_NFTABLES,
-#define NFNLGRP_NFTABLES NFNLGRP_NFTABLES
+#define NFNLGRP_NFTABLES NFNLGRP_NFTABLES
NFNLGRP_ACCT_QUOTA,
#define NFNLGRP_ACCT_QUOTA NFNLGRP_ACCT_QUOTA
+ NFNLGRP_NFTRACE,
+#define NFNLGRP_NFTRACE NFNLGRP_NFTRACE
__NFNLGRP_MAX,
};
#define NFNLGRP_MAX (__NFNLGRP_MAX - 1)
@@ -65,6 +58,24 @@ struct nfgenmsg {
#define NFNL_SUBSYS_ACCT 7
#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8
#define NFNL_SUBSYS_CTHELPER 9
-#define NFNL_SUBSYS_COUNT 10
+#define NFNL_SUBSYS_NFTABLES 10
+#define NFNL_SUBSYS_NFT_COMPAT 11
+#define NFNL_SUBSYS_COUNT 12
+
+/* Reserved control nfnetlink messages */
+#define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE
+#define NFNL_MSG_BATCH_END NLMSG_MIN_TYPE+1
+
+/**
+ * enum nfnl_batch_attributes - nfnetlink batch netlink attributes
+ *
+ * @NFNL_BATCH_GENID: generation ID for this changeset (NLA_U32)
+ */
+enum nfnl_batch_attributes {
+ NFNL_BATCH_UNSPEC,
+ NFNL_BATCH_GENID,
+ __NFNL_BATCH_MAX
+};
+#define NFNL_BATCH_MAX (__NFNL_BATCH_MAX - 1)
-#endif /* _UAPI_NFNETLINK_H */
+#endif /* _NFNETLINK_H */
diff --git a/include/linux-private/linux/netfilter/nfnetlink_compat.h b/include/linux-private/linux/netfilter/nfnetlink_compat.h
index ffb95036..ead71611 100644
--- a/include/linux-private/linux/netfilter/nfnetlink_compat.h
+++ b/include/linux-private/linux/netfilter/nfnetlink_compat.h
@@ -1,9 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _NFNETLINK_COMPAT_H
#define _NFNETLINK_COMPAT_H
#include <linux/types.h>
-#ifndef __KERNEL__
/* Old nfnetlink macros for userspace */
/* nfnetlink groups: Up to 32 maximum */
@@ -59,5 +59,4 @@ struct nfattr {
+ NLMSG_ALIGN(sizeof(struct nfgenmsg))))
#define NFM_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct nfgenmsg))
-#endif /* ! __KERNEL__ */
#endif /* _NFNETLINK_COMPAT_H */
diff --git a/include/linux-private/linux/netfilter/nfnetlink_conntrack.h b/include/linux-private/linux/netfilter/nfnetlink_conntrack.h
index 43bfe3e1..1d41810d 100644
--- a/include/linux-private/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/linux-private/linux/netfilter/nfnetlink_conntrack.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _IPCONNTRACK_NETLINK_H
#define _IPCONNTRACK_NETLINK_H
#include <linux/netfilter/nfnetlink.h>
@@ -9,6 +10,8 @@ enum cntl_msg_types {
IPCTNL_MSG_CT_GET_CTRZERO,
IPCTNL_MSG_CT_GET_STATS_CPU,
IPCTNL_MSG_CT_GET_STATS,
+ IPCTNL_MSG_CT_GET_DYING,
+ IPCTNL_MSG_CT_GET_UNCONFIRMED,
IPCTNL_MSG_MAX
};
@@ -40,13 +43,18 @@ enum ctattr_type {
CTA_ID,
CTA_NAT_DST,
CTA_TUPLE_MASTER,
- CTA_NAT_SEQ_ADJ_ORIG,
- CTA_NAT_SEQ_ADJ_REPLY,
+ CTA_SEQ_ADJ_ORIG,
+ CTA_NAT_SEQ_ADJ_ORIG = CTA_SEQ_ADJ_ORIG,
+ CTA_SEQ_ADJ_REPLY,
+ CTA_NAT_SEQ_ADJ_REPLY = CTA_SEQ_ADJ_REPLY,
CTA_SECMARK, /* obsolete */
CTA_ZONE,
CTA_SECCTX,
CTA_TIMESTAMP,
CTA_MARK_MASK,
+ CTA_LABELS,
+ CTA_LABELS_MASK,
+ CTA_SYNPROXY,
__CTA_MAX
};
#define CTA_MAX (__CTA_MAX - 1)
@@ -55,6 +63,7 @@ enum ctattr_tuple {
CTA_TUPLE_UNSPEC,
CTA_TUPLE_IP,
CTA_TUPLE_PROTO,
+ CTA_TUPLE_ZONE,
__CTA_TUPLE_MAX
};
#define CTA_TUPLE_MAX (__CTA_TUPLE_MAX - 1)
@@ -109,6 +118,7 @@ enum ctattr_protoinfo_dccp {
CTA_PROTOINFO_DCCP_STATE,
CTA_PROTOINFO_DCCP_ROLE,
CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
+ CTA_PROTOINFO_DCCP_PAD,
__CTA_PROTOINFO_DCCP_MAX,
};
#define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1)
@@ -128,6 +138,7 @@ enum ctattr_counters {
CTA_COUNTERS_BYTES, /* 64bit counters */
CTA_COUNTERS32_PACKETS, /* old 32bit counters, unused */
CTA_COUNTERS32_BYTES, /* old 32bit counters, unused */
+ CTA_COUNTERS_PAD,
__CTA_COUNTERS_MAX
};
#define CTA_COUNTERS_MAX (__CTA_COUNTERS_MAX - 1)
@@ -136,6 +147,7 @@ enum ctattr_tstamp {
CTA_TIMESTAMP_UNSPEC,
CTA_TIMESTAMP_START,
CTA_TIMESTAMP_STOP,
+ CTA_TIMESTAMP_PAD,
__CTA_TIMESTAMP_MAX
};
#define CTA_TIMESTAMP_MAX (__CTA_TIMESTAMP_MAX - 1)
@@ -161,6 +173,15 @@ enum ctattr_protonat {
};
#define CTA_PROTONAT_MAX (__CTA_PROTONAT_MAX - 1)
+enum ctattr_seqadj {
+ CTA_SEQADJ_UNSPEC,
+ CTA_SEQADJ_CORRECTION_POS,
+ CTA_SEQADJ_OFFSET_BEFORE,
+ CTA_SEQADJ_OFFSET_AFTER,
+ __CTA_SEQADJ_MAX
+};
+#define CTA_SEQADJ_MAX (__CTA_SEQADJ_MAX - 1)
+
enum ctattr_natseq {
CTA_NAT_SEQ_UNSPEC,
CTA_NAT_SEQ_CORRECTION_POS,
@@ -170,6 +191,15 @@ enum ctattr_natseq {
};
#define CTA_NAT_SEQ_MAX (__CTA_NAT_SEQ_MAX - 1)
+enum ctattr_synproxy {
+ CTA_SYNPROXY_UNSPEC,
+ CTA_SYNPROXY_ISN,
+ CTA_SYNPROXY_ITS,
+ CTA_SYNPROXY_TSOFF,
+ __CTA_SYNPROXY_MAX,
+};
+#define CTA_SYNPROXY_MAX (__CTA_SYNPROXY_MAX - 1)
+
enum ctattr_expect {
CTA_EXPECT_UNSPEC,
CTA_EXPECT_MASTER,
@@ -212,13 +242,13 @@ enum ctattr_secctx {
enum ctattr_stats_cpu {
CTA_STATS_UNSPEC,
- CTA_STATS_SEARCHED,
+ CTA_STATS_SEARCHED, /* no longer used */
CTA_STATS_FOUND,
- CTA_STATS_NEW,
+ CTA_STATS_NEW, /* no longer used */
CTA_STATS_INVALID,
CTA_STATS_IGNORE,
- CTA_STATS_DELETE,
- CTA_STATS_DELETE_LIST,
+ CTA_STATS_DELETE, /* no longer used */
+ CTA_STATS_DELETE_LIST, /* no longer used */
CTA_STATS_INSERT,
CTA_STATS_INSERT_FAILED,
CTA_STATS_DROP,
@@ -232,6 +262,7 @@ enum ctattr_stats_cpu {
enum ctattr_stats_global {
CTA_STATS_GLOBAL_UNSPEC,
CTA_STATS_GLOBAL_ENTRIES,
+ CTA_STATS_GLOBAL_MAX_ENTRIES,
__CTA_STATS_GLOBAL_MAX,
};
#define CTA_STATS_GLOBAL_MAX (__CTA_STATS_GLOBAL_MAX - 1)
diff --git a/include/linux-private/linux/netfilter/nfnetlink_log.h b/include/linux-private/linux/netfilter/nfnetlink_log.h
index 2cfbf139..20983cb1 100644
--- a/include/linux-private/linux/netfilter/nfnetlink_log.h
+++ b/include/linux-private/linux/netfilter/nfnetlink_log.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _NFNETLINK_LOG_H
#define _NFNETLINK_LOG_H
@@ -5,10 +6,6 @@
* and not any kind of function definitions. It is shared between kernel and
* userspace. Don't put kernel specific stuff in here */
-#ifndef __aligned_be64
-#define __aligned_be64 u_int64_t __attribute__((aligned(8)))
-#endif
-
#include <linux/types.h>
#include <linux/netfilter/nfnetlink.h>
@@ -55,6 +52,8 @@ enum nfulnl_attr_type {
NFULA_HWTYPE, /* hardware type */
NFULA_HWHEADER, /* hardware header */
NFULA_HWLEN, /* hardware header length */
+ NFULA_CT, /* nf_conntrack_netlink.h */
+ NFULA_CT_INFO, /* enum ip_conntrack_info */
__NFULA_MAX
};
@@ -97,5 +96,6 @@ enum nfulnl_attr_config {
#define NFULNL_CFG_F_SEQ 0x0001
#define NFULNL_CFG_F_SEQ_GLOBAL 0x0002
+#define NFULNL_CFG_F_CONNTRACK 0x0004
#endif /* _NFNETLINK_LOG_H */
diff --git a/include/linux-private/linux/netfilter/nfnetlink_queue.h b/include/linux-private/linux/netfilter/nfnetlink_queue.h
index 95af967d..bcb2cb5d 100644
--- a/include/linux-private/linux/netfilter/nfnetlink_queue.h
+++ b/include/linux-private/linux/netfilter/nfnetlink_queue.h
@@ -1,13 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _NFNETLINK_QUEUE_H
#define _NFNETLINK_QUEUE_H
#include <linux/types.h>
#include <linux/netfilter/nfnetlink.h>
-#ifndef __aligned_be64
-#define __aligned_be64 u_int64_t __attribute__((aligned(8)))
-#endif
-
enum nfqnl_msg_types {
NFQNL_MSG_PACKET, /* packet from kernel to userspace */
NFQNL_MSG_VERDICT, /* verdict from userspace to kernel */
@@ -34,6 +31,14 @@ struct nfqnl_msg_packet_timestamp {
__aligned_be64 usec;
};
+enum nfqnl_vlan_attr {
+ NFQA_VLAN_UNSPEC,
+ NFQA_VLAN_PROTO, /* __be16 skb vlan_proto */
+ NFQA_VLAN_TCI, /* __be16 skb htons(vlan_tci) */
+ __NFQA_VLAN_MAX,
+};
+#define NFQA_VLAN_MAX (__NFQA_VLAN_MAX - 1)
+
enum nfqnl_attr_type {
NFQA_UNSPEC,
NFQA_PACKET_HDR,
@@ -49,6 +54,13 @@ enum nfqnl_attr_type {
NFQA_CT, /* nf_conntrack_netlink.h */
NFQA_CT_INFO, /* enum ip_conntrack_info */
NFQA_CAP_LEN, /* __u32 length of captured packet */
+ NFQA_SKB_INFO, /* __u32 skb meta information */
+ NFQA_EXP, /* nf_conntrack_netlink.h */
+ NFQA_UID, /* __u32 sk uid */
+ NFQA_GID, /* __u32 sk gid */
+ NFQA_SECCTX, /* security context string */
+ NFQA_VLAN, /* nested attribute: packet vlan info */
+ NFQA_L2HDR, /* full L2 header */
__NFQA_MAX
};
@@ -100,6 +112,17 @@ enum nfqnl_attr_config {
/* Flags for NFQA_CFG_FLAGS */
#define NFQA_CFG_F_FAIL_OPEN (1 << 0)
#define NFQA_CFG_F_CONNTRACK (1 << 1)
-#define NFQA_CFG_F_MAX (1 << 2)
+#define NFQA_CFG_F_GSO (1 << 2)
+#define NFQA_CFG_F_UID_GID (1 << 3)
+#define NFQA_CFG_F_SECCTX (1 << 4)
+#define NFQA_CFG_F_MAX (1 << 5)
+
+/* flags for NFQA_SKB_INFO */
+/* packet appears to have wrong checksums, but they are ok */
+#define NFQA_SKB_CSUMNOTREADY (1 << 0)
+/* packet is GSO (i.e., exceeds device mtu) */
+#define NFQA_SKB_GSO (1 << 1)
+/* csum not validated (incoming device doesn't support hw checksum, etc.) */
+#define NFQA_SKB_CSUM_NOTVERIFIED (1 << 2)
#endif /* _NFNETLINK_QUEUE_H */
diff --git a/include/linux-private/linux/netlink.h b/include/linux-private/linux/netlink.h
index 39252548..0b2c29bd 100644
--- a/include/linux-private/linux/netlink.h
+++ b/include/linux-private/linux/netlink.h
@@ -1,14 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_NETLINK_H
#define __LINUX_NETLINK_H
-#include <linux/socket.h> /* for sa_family_t */
+#include <linux/kernel.h>
+#include <linux/socket.h> /* for __kernel_sa_family_t */
#include <linux/types.h>
#define NETLINK_ROUTE 0 /* Routing/device hook */
#define NETLINK_UNUSED 1 /* Unused number */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
-#define NETLINK_FIREWALL 3 /* Firewalling hook */
-#define NETLINK_INET_DIAG 4 /* INET socket monitoring */
+#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */
+#define NETLINK_SOCK_DIAG 4 /* socket monitoring */
#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
#define NETLINK_XFRM 6 /* ipsec */
#define NETLINK_SELINUX 7 /* SELinux event notifications */
@@ -25,11 +27,15 @@
#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
#define NETLINK_ECRYPTFS 19
#define NETLINK_RDMA 20
+#define NETLINK_CRYPTO 21 /* Crypto layer */
+#define NETLINK_SMC 22 /* SMC monitoring */
+
+#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG
#define MAX_LINKS 32
struct sockaddr_nl {
- sa_family_t nl_family; /* AF_NETLINK */
+ __kernel_sa_family_t nl_family; /* AF_NETLINK */
unsigned short nl_pad; /* zero */
__u32 nl_pid; /* port ID */
__u32 nl_groups; /* multicast groups mask */
@@ -45,11 +51,12 @@ struct nlmsghdr {
/* Flags values */
-#define NLM_F_REQUEST 1 /* It is request message. */
-#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */
-#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */
-#define NLM_F_ECHO 8 /* Echo this request */
-#define NLM_F_DUMP_INTR 16 /* Dump was inconsistent due to sequence change */
+#define NLM_F_REQUEST 0x01 /* It is request message. */
+#define NLM_F_MULTI 0x02 /* Multipart message, terminated by NLMSG_DONE */
+#define NLM_F_ACK 0x04 /* Reply with ack, with zero or error code */
+#define NLM_F_ECHO 0x08 /* Echo this request */
+#define NLM_F_DUMP_INTR 0x10 /* Dump was inconsistent due to sequence change */
+#define NLM_F_DUMP_FILTERED 0x20 /* Dump was filtered as requested */
/* Modifiers to GET request */
#define NLM_F_ROOT 0x100 /* specify tree root */
@@ -63,6 +70,13 @@ struct nlmsghdr {
#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
#define NLM_F_APPEND 0x800 /* Add to end of list */
+/* Modifiers to DELETE request */
+#define NLM_F_NONREC 0x100 /* Do not delete recursively */
+
+/* Flags for ACK message */
+#define NLM_F_CAPPED 0x100 /* request was capped */
+#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
+
/*
4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
4.4BSD CHANGE NLM_F_REPLACE
@@ -75,7 +89,7 @@ struct nlmsghdr {
#define NLMSG_ALIGNTO 4U
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
-#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(NLMSG_HDRLEN))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
@@ -95,18 +109,84 @@ struct nlmsghdr {
struct nlmsgerr {
int error;
struct nlmsghdr msg;
+ /*
+ * followed by the message contents unless NETLINK_CAP_ACK was set
+ * or the ACK indicates success (error == 0)
+ * message length is aligned with NLMSG_ALIGN()
+ */
+ /*
+ * followed by TLVs defined in enum nlmsgerr_attrs
+ * if NETLINK_EXT_ACK was set
+ */
+};
+
+/**
+ * enum nlmsgerr_attrs - nlmsgerr attributes
+ * @NLMSGERR_ATTR_UNUSED: unused
+ * @NLMSGERR_ATTR_MSG: error message string (string)
+ * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original
+ * message, counting from the beginning of the header (u32)
+ * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to
+ * be used - in the success case - to identify a created
+ * object or operation or similar (binary)
+ * @__NLMSGERR_ATTR_MAX: number of attributes
+ * @NLMSGERR_ATTR_MAX: highest attribute number
+ */
+enum nlmsgerr_attrs {
+ NLMSGERR_ATTR_UNUSED,
+ NLMSGERR_ATTR_MSG,
+ NLMSGERR_ATTR_OFFS,
+ NLMSGERR_ATTR_COOKIE,
+
+ __NLMSGERR_ATTR_MAX,
+ NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
};
-#define NETLINK_ADD_MEMBERSHIP 1
-#define NETLINK_DROP_MEMBERSHIP 2
-#define NETLINK_PKTINFO 3
-#define NETLINK_BROADCAST_ERROR 4
-#define NETLINK_NO_ENOBUFS 5
+#define NETLINK_ADD_MEMBERSHIP 1
+#define NETLINK_DROP_MEMBERSHIP 2
+#define NETLINK_PKTINFO 3
+#define NETLINK_BROADCAST_ERROR 4
+#define NETLINK_NO_ENOBUFS 5
+#define NETLINK_RX_RING 6
+#define NETLINK_TX_RING 7
+#define NETLINK_LISTEN_ALL_NSID 8
+#define NETLINK_LIST_MEMBERSHIPS 9
+#define NETLINK_CAP_ACK 10
+#define NETLINK_EXT_ACK 11
struct nl_pktinfo {
__u32 group;
};
+struct nl_mmap_req {
+ unsigned int nm_block_size;
+ unsigned int nm_block_nr;
+ unsigned int nm_frame_size;
+ unsigned int nm_frame_nr;
+};
+
+struct nl_mmap_hdr {
+ unsigned int nm_status;
+ unsigned int nm_len;
+ __u32 nm_group;
+ /* credentials */
+ __u32 nm_pid;
+ __u32 nm_uid;
+ __u32 nm_gid;
+};
+
+enum nl_mmap_status {
+ NL_MMAP_STATUS_UNUSED,
+ NL_MMAP_STATUS_RESERVED,
+ NL_MMAP_STATUS_VALID,
+ NL_MMAP_STATUS_COPY,
+ NL_MMAP_STATUS_SKIP,
+};
+
+#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO
+#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
+#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+
#define NET_MAJOR 36 /* Major 36 is reserved for networking */
enum {
@@ -146,4 +226,22 @@ struct nlattr {
#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
-#endif /* __LINUX_NETLINK_H */
+/* Generic 32 bitflags attribute content sent to the kernel.
+ *
+ * The value is a bitmap that defines the values being set
+ * The selector is a bitmask that defines which value is legit
+ *
+ * Examples:
+ * value = 0x0, and selector = 0x1
+ * implies we are selecting bit 1 and we want to set its value to 0.
+ *
+ * value = 0x2, and selector = 0x2
+ * implies we are selecting bit 2 and we want to set its value to 1.
+ *
+ */
+struct nla_bitfield32 {
+ __u32 value;
+ __u32 selector;
+};
+
+#endif /* __LINUX_NETLINK_H */
diff --git a/include/linux-private/linux/pkt_cls.h b/include/linux-private/linux/pkt_cls.h
index defbde20..be382fb0 100644
--- a/include/linux-private/linux/pkt_cls.h
+++ b/include/linux-private/linux/pkt_cls.h
@@ -1,78 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_PKT_CLS_H
#define __LINUX_PKT_CLS_H
#include <linux/types.h>
#include <linux/pkt_sched.h>
-/* I think i could have done better macros ; for now this is stolen from
- * some arch/mips code - jhs
-*/
-#define _TC_MAKE32(x) ((x))
-
-#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n))
-#define _TC_MAKEMASK(v,n) (_TC_MAKE32((_TC_MAKE32(1)<<(v))-1) << _TC_MAKE32(n))
-#define _TC_MAKEVALUE(v,n) (_TC_MAKE32(v) << _TC_MAKE32(n))
-#define _TC_GETVALUE(v,n,m) ((_TC_MAKE32(v) & _TC_MAKE32(m)) >> _TC_MAKE32(n))
-
-/* verdict bit breakdown
- *
-bit 0: when set -> this packet has been munged already
-
-bit 1: when set -> It is ok to munge this packet
-
-bit 2,3,4,5: Reclassify counter - sort of reverse TTL - if exceeded
-assume loop
-
-bit 6,7: Where this packet was last seen
-0: Above the transmit example at the socket level
-1: on the Ingress
-2: on the Egress
-
-bit 8: when set --> Request not to classify on ingress.
-
-bits 9,10,11: redirect counter - redirect TTL. Loop avoidance
-
- *
- * */
-
-#define TC_MUNGED _TC_MAKEMASK1(0)
-#define SET_TC_MUNGED(v) ( TC_MUNGED | (v & ~TC_MUNGED))
-#define CLR_TC_MUNGED(v) ( v & ~TC_MUNGED)
-
-#define TC_OK2MUNGE _TC_MAKEMASK1(1)
-#define SET_TC_OK2MUNGE(v) ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE))
-#define CLR_TC_OK2MUNGE(v) ( v & ~TC_OK2MUNGE)
-
-#define S_TC_VERD _TC_MAKE32(2)
-#define M_TC_VERD _TC_MAKEMASK(4,S_TC_VERD)
-#define G_TC_VERD(x) _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD)
-#define V_TC_VERD(x) _TC_MAKEVALUE(x,S_TC_VERD)
-#define SET_TC_VERD(v,n) ((V_TC_VERD(n)) | (v & ~M_TC_VERD))
-
-#define S_TC_FROM _TC_MAKE32(6)
-#define M_TC_FROM _TC_MAKEMASK(2,S_TC_FROM)
-#define G_TC_FROM(x) _TC_GETVALUE(x,S_TC_FROM,M_TC_FROM)
-#define V_TC_FROM(x) _TC_MAKEVALUE(x,S_TC_FROM)
-#define SET_TC_FROM(v,n) ((V_TC_FROM(n)) | (v & ~M_TC_FROM))
-#define AT_STACK 0x0
-#define AT_INGRESS 0x1
-#define AT_EGRESS 0x2
-
-#define TC_NCLS _TC_MAKEMASK1(8)
-#define SET_TC_NCLS(v) ( TC_NCLS | (v & ~TC_NCLS))
-#define CLR_TC_NCLS(v) ( v & ~TC_NCLS)
-
-#define S_TC_RTTL _TC_MAKE32(9)
-#define M_TC_RTTL _TC_MAKEMASK(3,S_TC_RTTL)
-#define G_TC_RTTL(x) _TC_GETVALUE(x,S_TC_RTTL,M_TC_RTTL)
-#define V_TC_RTTL(x) _TC_MAKEVALUE(x,S_TC_RTTL)
-#define SET_TC_RTTL(v,n) ((V_TC_RTTL(n)) | (v & ~M_TC_RTTL))
-
-#define S_TC_AT _TC_MAKE32(12)
-#define M_TC_AT _TC_MAKEMASK(2,S_TC_AT)
-#define G_TC_AT(x) _TC_GETVALUE(x,S_TC_AT,M_TC_AT)
-#define V_TC_AT(x) _TC_MAKEVALUE(x,S_TC_AT)
-#define SET_TC_AT(v,n) ((V_TC_AT(n)) | (v & ~M_TC_AT))
+#define TC_COOKIE_MAX_SIZE 16
/* Action attributes */
enum {
@@ -81,6 +14,8 @@ enum {
TCA_ACT_OPTIONS,
TCA_ACT_INDEX,
TCA_ACT_STATS,
+ TCA_ACT_PAD,
+ TCA_ACT_COOKIE,
__TCA_ACT_MAX
};
@@ -93,8 +28,6 @@ enum {
#define TCA_ACT_NOUNBIND 0
#define TCA_ACT_REPLACE 1
#define TCA_ACT_NOREPLACE 0
-#define MAX_REC_LOOP 4
-#define MAX_RED_LOOP 4
#define TC_ACT_UNSPEC (-1)
#define TC_ACT_OK 0
@@ -104,7 +37,31 @@ enum {
#define TC_ACT_STOLEN 4
#define TC_ACT_QUEUED 5
#define TC_ACT_REPEAT 6
-#define TC_ACT_JUMP 0x10000000
+#define TC_ACT_REDIRECT 7
+#define TC_ACT_TRAP 8 /* For hw path, this means "trap to cpu"
+ * and don't further process the frame
+ * in hardware. For sw path, this is
+ * equivalent of TC_ACT_STOLEN - drop
+ * the skb and act like everything
+ * is alright.
+ */
+#define TC_ACT_VALUE_MAX TC_ACT_TRAP
+
+/* There is a special kind of actions called "extended actions",
+ * which need a value parameter. These have a local opcode located in
+ * the highest nibble, starting from 1. The rest of the bits
+ * are used to carry the value. These two parts together make
+ * a combined opcode.
+ */
+#define __TC_ACT_EXT_SHIFT 28
+#define __TC_ACT_EXT(local) ((local) << __TC_ACT_EXT_SHIFT)
+#define TC_ACT_EXT_VAL_MASK ((1 << __TC_ACT_EXT_SHIFT) - 1)
+#define TC_ACT_EXT_OPCODE(combined) ((combined) & (~TC_ACT_EXT_VAL_MASK))
+#define TC_ACT_EXT_CMP(combined, opcode) (TC_ACT_EXT_OPCODE(combined) == opcode)
+
+#define TC_ACT_JUMP __TC_ACT_EXT(1)
+#define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2)
+#define TC_ACT_EXT_OPCODE_MAX TC_ACT_GOTO_CHAIN
/* Action type identifiers*/
enum {
@@ -130,8 +87,8 @@ struct tc_police {
__u32 mtu;
struct tc_ratespec rate;
struct tc_ratespec peakrate;
- int refcnt;
- int bindcnt;
+ int refcnt;
+ int bindcnt;
__u32 capab;
};
@@ -139,10 +96,11 @@ struct tcf_t {
__u64 install;
__u64 lastuse;
__u64 expires;
+ __u64 firstuse;
};
struct tc_cnt {
- int refcnt;
+ int refcnt;
int bindcnt;
};
@@ -160,12 +118,21 @@ enum {
TCA_POLICE_PEAKRATE,
TCA_POLICE_AVRATE,
TCA_POLICE_RESULT,
+ TCA_POLICE_TM,
+ TCA_POLICE_PAD,
__TCA_POLICE_MAX
#define TCA_POLICE_RESULT TCA_POLICE_RESULT
};
#define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1)
+/* tca flags definitions */
+#define TCA_CLS_FLAGS_SKIP_HW (1 << 0) /* don't offload filter to HW */
+#define TCA_CLS_FLAGS_SKIP_SW (1 << 1) /* don't use filter in SW */
+#define TCA_CLS_FLAGS_IN_HW (1 << 2) /* filter is offloaded to HW */
+#define TCA_CLS_FLAGS_NOT_IN_HW (1 << 3) /* filter isn't offloaded to HW */
+#define TCA_CLS_FLAGS_VERBOSE (1 << 4) /* verbose logging */
+
/* U32 filters */
#define TC_U32_HTID(h) ((h)&0xFFF00000)
@@ -184,10 +151,12 @@ enum {
TCA_U32_DIVISOR,
TCA_U32_SEL,
TCA_U32_POLICE,
- TCA_U32_ACT,
+ TCA_U32_ACT,
TCA_U32_INDEV,
TCA_U32_PCNT,
TCA_U32_MARK,
+ TCA_U32_FLAGS,
+ TCA_U32_PAD,
__TCA_U32_MAX
};
@@ -388,6 +357,177 @@ enum {
#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1)
+/* BPF classifier */
+
+#define TCA_BPF_FLAG_ACT_DIRECT (1 << 0)
+
+enum {
+ TCA_BPF_UNSPEC,
+ TCA_BPF_ACT,
+ TCA_BPF_POLICE,
+ TCA_BPF_CLASSID,
+ TCA_BPF_OPS_LEN,
+ TCA_BPF_OPS,
+ TCA_BPF_FD,
+ TCA_BPF_NAME,
+ TCA_BPF_FLAGS,
+ TCA_BPF_FLAGS_GEN,
+ TCA_BPF_TAG,
+ TCA_BPF_ID,
+ __TCA_BPF_MAX,
+};
+
+#define TCA_BPF_MAX (__TCA_BPF_MAX - 1)
+
+/* Flower classifier */
+
+enum {
+ TCA_FLOWER_UNSPEC,
+ TCA_FLOWER_CLASSID,
+ TCA_FLOWER_INDEV,
+ TCA_FLOWER_ACT,
+ TCA_FLOWER_KEY_ETH_DST, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ETH_DST_MASK, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ETH_SRC, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ETH_SRC_MASK, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ETH_TYPE, /* be16 */
+ TCA_FLOWER_KEY_IP_PROTO, /* u8 */
+ TCA_FLOWER_KEY_IPV4_SRC, /* be32 */
+ TCA_FLOWER_KEY_IPV4_SRC_MASK, /* be32 */
+ TCA_FLOWER_KEY_IPV4_DST, /* be32 */
+ TCA_FLOWER_KEY_IPV4_DST_MASK, /* be32 */
+ TCA_FLOWER_KEY_IPV6_SRC, /* struct in6_addr */
+ TCA_FLOWER_KEY_IPV6_SRC_MASK, /* struct in6_addr */
+ TCA_FLOWER_KEY_IPV6_DST, /* struct in6_addr */
+ TCA_FLOWER_KEY_IPV6_DST_MASK, /* struct in6_addr */
+ TCA_FLOWER_KEY_TCP_SRC, /* be16 */
+ TCA_FLOWER_KEY_TCP_DST, /* be16 */
+ TCA_FLOWER_KEY_UDP_SRC, /* be16 */
+ TCA_FLOWER_KEY_UDP_DST, /* be16 */
+
+ TCA_FLOWER_FLAGS,
+ TCA_FLOWER_KEY_VLAN_ID, /* be16 */
+ TCA_FLOWER_KEY_VLAN_PRIO, /* u8 */
+ TCA_FLOWER_KEY_VLAN_ETH_TYPE, /* be16 */
+
+ TCA_FLOWER_KEY_ENC_KEY_ID, /* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_SRC, /* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,/* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_DST, /* be32 */
+ TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,/* be32 */
+ TCA_FLOWER_KEY_ENC_IPV6_SRC, /* struct in6_addr */
+ TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,/* struct in6_addr */
+ TCA_FLOWER_KEY_ENC_IPV6_DST, /* struct in6_addr */
+ TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,/* struct in6_addr */
+
+ TCA_FLOWER_KEY_TCP_SRC_MASK, /* be16 */
+ TCA_FLOWER_KEY_TCP_DST_MASK, /* be16 */
+ TCA_FLOWER_KEY_UDP_SRC_MASK, /* be16 */
+ TCA_FLOWER_KEY_UDP_DST_MASK, /* be16 */
+ TCA_FLOWER_KEY_SCTP_SRC_MASK, /* be16 */
+ TCA_FLOWER_KEY_SCTP_DST_MASK, /* be16 */
+
+ TCA_FLOWER_KEY_SCTP_SRC, /* be16 */
+ TCA_FLOWER_KEY_SCTP_DST, /* be16 */
+
+ TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, /* be16 */
+ TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, /* be16 */
+ TCA_FLOWER_KEY_ENC_UDP_DST_PORT, /* be16 */
+ TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, /* be16 */
+
+ TCA_FLOWER_KEY_FLAGS, /* be32 */
+ TCA_FLOWER_KEY_FLAGS_MASK, /* be32 */
+
+ TCA_FLOWER_KEY_ICMPV4_CODE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV4_CODE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV4_TYPE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV6_CODE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV6_CODE_MASK,/* u8 */
+ TCA_FLOWER_KEY_ICMPV6_TYPE, /* u8 */
+ TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,/* u8 */
+
+ TCA_FLOWER_KEY_ARP_SIP, /* be32 */
+ TCA_FLOWER_KEY_ARP_SIP_MASK, /* be32 */
+ TCA_FLOWER_KEY_ARP_TIP, /* be32 */
+ TCA_FLOWER_KEY_ARP_TIP_MASK, /* be32 */
+ TCA_FLOWER_KEY_ARP_OP, /* u8 */
+ TCA_FLOWER_KEY_ARP_OP_MASK, /* u8 */
+ TCA_FLOWER_KEY_ARP_SHA, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ARP_SHA_MASK, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ARP_THA, /* ETH_ALEN */
+ TCA_FLOWER_KEY_ARP_THA_MASK, /* ETH_ALEN */
+
+ TCA_FLOWER_KEY_MPLS_TTL, /* u8 - 8 bits */
+ TCA_FLOWER_KEY_MPLS_BOS, /* u8 - 1 bit */
+ TCA_FLOWER_KEY_MPLS_TC, /* u8 - 3 bits */
+ TCA_FLOWER_KEY_MPLS_LABEL, /* be32 - 20 bits */
+
+ TCA_FLOWER_KEY_TCP_FLAGS, /* be16 */
+ TCA_FLOWER_KEY_TCP_FLAGS_MASK, /* be16 */
+
+ TCA_FLOWER_KEY_IP_TOS, /* u8 */
+ TCA_FLOWER_KEY_IP_TOS_MASK, /* u8 */
+ TCA_FLOWER_KEY_IP_TTL, /* u8 */
+ TCA_FLOWER_KEY_IP_TTL_MASK, /* u8 */
+
+ TCA_FLOWER_KEY_CVLAN_ID, /* be16 */
+ TCA_FLOWER_KEY_CVLAN_PRIO, /* u8 */
+ TCA_FLOWER_KEY_CVLAN_ETH_TYPE, /* be16 */
+
+ TCA_FLOWER_KEY_ENC_IP_TOS, /* u8 */
+ TCA_FLOWER_KEY_ENC_IP_TOS_MASK, /* u8 */
+ TCA_FLOWER_KEY_ENC_IP_TTL, /* u8 */
+ TCA_FLOWER_KEY_ENC_IP_TTL_MASK, /* u8 */
+
+ TCA_FLOWER_KEY_ENC_OPTS,
+ TCA_FLOWER_KEY_ENC_OPTS_MASK,
+
+ __TCA_FLOWER_MAX,
+};
+
+#define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1)
+
+enum {
+ TCA_FLOWER_KEY_ENC_OPTS_UNSPEC,
+ TCA_FLOWER_KEY_ENC_OPTS_GENEVE, /* Nested
+ * TCA_FLOWER_KEY_ENC_OPT_GENEVE_
+ * attributes
+ */
+ __TCA_FLOWER_KEY_ENC_OPTS_MAX,
+};
+
+#define TCA_FLOWER_KEY_ENC_OPTS_MAX (__TCA_FLOWER_KEY_ENC_OPTS_MAX - 1)
+
+enum {
+ TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC,
+ TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, /* u16 */
+ TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, /* u8 */
+ TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, /* 4 to 128 bytes */
+
+ __TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX,
+};
+
+#define TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX \
+ (__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX - 1)
+
+enum {
+ TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0),
+ TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1),
+};
+
+/* Match-all classifier */
+
+enum {
+ TCA_MATCHALL_UNSPEC,
+ TCA_MATCHALL_CLASSID,
+ TCA_MATCHALL_ACT,
+ TCA_MATCHALL_FLAGS,
+ __TCA_MATCHALL_MAX,
+};
+
+#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1)
+
/* Extended Matches */
struct tcf_ematch_tree_hdr {
@@ -451,8 +591,11 @@ enum {
#define TCF_EM_U32 3
#define TCF_EM_META 4
#define TCF_EM_TEXT 5
-#define TCF_EM_VLAN 6
-#define TCF_EM_MAX 6
+#define TCF_EM_VLAN 6
+#define TCF_EM_CANID 7
+#define TCF_EM_IPSET 8
+#define TCF_EM_IPT 9
+#define TCF_EM_MAX 9
enum {
TCF_EM_PROG_TC
diff --git a/include/linux-private/linux/pkt_sched.h b/include/linux-private/linux/pkt_sched.h
index a0837a0b..8975fd1a 100644
--- a/include/linux-private/linux/pkt_sched.h
+++ b/include/linux-private/linux/pkt_sched.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_PKT_SCHED_H
#define __LINUX_PKT_SCHED_H
@@ -30,7 +31,7 @@
*/
struct tc_stats {
- __u64 bytes; /* NUmber of enqueues bytes */
+ __u64 bytes; /* Number of enqueued bytes */
__u32 packets; /* Number of enqueued packets */
__u32 drops; /* Packets dropped because of lack of resources */
__u32 overlimits; /* Number of throttle events when this
@@ -72,10 +73,23 @@ struct tc_estimator {
#define TC_H_UNSPEC (0U)
#define TC_H_ROOT (0xFFFFFFFFU)
#define TC_H_INGRESS (0xFFFFFFF1U)
+#define TC_H_CLSACT TC_H_INGRESS
+
+#define TC_H_MIN_PRIORITY 0xFFE0U
+#define TC_H_MIN_INGRESS 0xFFF2U
+#define TC_H_MIN_EGRESS 0xFFF3U
+
+/* Need to corrospond to iproute2 tc/tc_core.h "enum link_layer" */
+enum tc_link_layer {
+ TC_LINKLAYER_UNAWARE, /* Indicate unaware old iproute2 util */
+ TC_LINKLAYER_ETHERNET,
+ TC_LINKLAYER_ATM,
+};
+#define TC_LINKLAYER_MASK 0x0F /* limit use to lower 4 bits */
struct tc_ratespec {
unsigned char cell_log;
- unsigned char __reserved;
+ __u8 linklayer; /* lower 4 bits */
unsigned short overhead;
short cell_align;
unsigned short mpu;
@@ -110,6 +124,21 @@ struct tc_fifo_qopt {
__u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */
};
+/* SKBPRIO section */
+
+/*
+ * Priorities go from zero to (SKBPRIO_MAX_PRIORITY - 1).
+ * SKBPRIO_MAX_PRIORITY should be at least 64 in order for skbprio to be able
+ * to map one to one the DS field of IPV4 and IPV6 headers.
+ * Memory allocation grows linearly with SKBPRIO_MAX_PRIORITY.
+ */
+
+#define SKBPRIO_MAX_PRIORITY 64
+
+struct tc_skbprio_qopt {
+ __u32 limit; /* Queue length in packets. */
+};
+
/* PRIO section */
#define TCQ_PRIO_BANDS 16
@@ -135,17 +164,17 @@ struct tc_multiq_qopt {
#define TCQ_PLUG_LIMIT 3
struct tc_plug_qopt {
- /* TCQ_PLUG_BUFFER: Inset a plug into the queue and
- * buffer any incoming packets
- * TCQ_PLUG_RELEASE_ONE: Dequeue packets from queue head
- * to beginning of the next plug.
- * TCQ_PLUG_RELEASE_INDEFINITE: Dequeue all packets from queue.
- * Stop buffering packets until the next TCQ_PLUG_BUFFER
- * command is received (just act as a pass-thru queue).
- * TCQ_PLUG_LIMIT: Increase/decrease queue size
- */
- int action;
- __u32 limit;
+ /* TCQ_PLUG_BUFFER: Inset a plug into the queue and
+ * buffer any incoming packets
+ * TCQ_PLUG_RELEASE_ONE: Dequeue packets from queue head
+ * to beginning of the next plug.
+ * TCQ_PLUG_RELEASE_INDEFINITE: Dequeue all packets from queue.
+ * Stop buffering packets until the next TCQ_PLUG_BUFFER
+ * command is received (just act as a pass-thru queue).
+ * TCQ_PLUG_LIMIT: Increase/decrease queue size
+ */
+ int action;
+ __u32 limit;
};
/* TBF section */
@@ -163,6 +192,11 @@ enum {
TCA_TBF_PARMS,
TCA_TBF_RTAB,
TCA_TBF_PTAB,
+ TCA_TBF_RATE64,
+ TCA_TBF_PRATE64,
+ TCA_TBF_BURST,
+ TCA_TBF_PBURST,
+ TCA_TBF_PAD,
__TCA_TBF_MAX,
};
@@ -183,25 +217,44 @@ struct tc_sfq_qopt {
unsigned flows; /* Maximal number of flows */
};
+struct tc_sfqred_stats {
+ __u32 prob_drop; /* Early drops, below max threshold */
+ __u32 forced_drop; /* Early drops, after max threshold */
+ __u32 prob_mark; /* Marked packets, below max threshold */
+ __u32 forced_mark; /* Marked packets, after max threshold */
+ __u32 prob_mark_head; /* Marked packets, below max threshold */
+ __u32 forced_mark_head;/* Marked packets, after max threshold */
+};
+
+struct tc_sfq_qopt_v1 {
+ struct tc_sfq_qopt v0;
+ unsigned int depth; /* max number of packets per flow */
+ unsigned int headdrop;
+/* SFQRED parameters */
+ __u32 limit; /* HARD maximal flow queue length (bytes) */
+ __u32 qth_min; /* Min average length threshold (bytes) */
+ __u32 qth_max; /* Max average length threshold (bytes) */
+ unsigned char Wlog; /* log(W) */
+ unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */
+ unsigned char Scell_log; /* cell size for idle damping */
+ unsigned char flags;
+ __u32 max_P; /* probability, high resolution */
+/* SFQRED stats */
+ struct tc_sfqred_stats stats;
+};
+
+
struct tc_sfq_xstats {
__s32 allot;
};
-/*
- * NOTE: limit, divisor and flows are hardwired to code at the moment.
- *
- * limit=flows=128, divisor=1024;
- *
- * The only reason for this is efficiency, it is possible
- * to change these parameters in compile time.
- */
-
/* RED section */
enum {
TCA_RED_UNSPEC,
TCA_RED_PARMS,
TCA_RED_STAB,
+ TCA_RED_MAX_P,
__TCA_RED_MAX,
};
@@ -215,8 +268,9 @@ struct tc_red_qopt {
unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */
unsigned char Scell_log; /* cell size for idle damping */
unsigned char flags;
-#define TC_RED_ECN 1
-#define TC_RED_HARDDROP 2
+#define TC_RED_ECN 1
+#define TC_RED_HARDDROP 2
+#define TC_RED_ADAPTATIVE 4
};
struct tc_red_xstats {
@@ -235,7 +289,9 @@ enum {
TCA_GRED_PARMS,
TCA_GRED_STAB,
TCA_GRED_DPS,
- __TCA_GRED_MAX,
+ TCA_GRED_MAX_P,
+ TCA_GRED_LIMIT,
+ __TCA_GRED_MAX,
};
#define TCA_GRED_MAX (__TCA_GRED_MAX - 1)
@@ -274,6 +330,7 @@ enum {
TCA_CHOKE_UNSPEC,
TCA_CHOKE_PARMS,
TCA_CHOKE_STAB,
+ TCA_CHOKE_MAX_P,
__TCA_CHOKE_MAX,
};
@@ -318,7 +375,7 @@ struct tc_htb_glob {
__u32 debug; /* debug flags */
/* stats */
- __u32 direct_pkts; /* count of non shapped packets */
+ __u32 direct_pkts; /* count of non shaped packets */
};
enum {
TCA_HTB_UNSPEC,
@@ -326,6 +383,10 @@ enum {
TCA_HTB_INIT,
TCA_HTB_CTAB,
TCA_HTB_RTAB,
+ TCA_HTB_DIRECT_QLEN,
+ TCA_HTB_RATE64,
+ TCA_HTB_CEIL64,
+ TCA_HTB_PAD,
__TCA_HTB_MAX,
};
@@ -462,21 +523,6 @@ enum {
#define TCA_DSMARK_MAX (__TCA_DSMARK_MAX - 1)
-/* fq_codel section */
-
-enum {
- TCA_FQ_CODEL_UNSPEC,
- TCA_FQ_CODEL_TARGET,
- TCA_FQ_CODEL_LIMIT,
- TCA_FQ_CODEL_INTERVAL,
- TCA_FQ_CODEL_ECN,
- TCA_FQ_CODEL_FLOWS,
- TCA_FQ_CODEL_QUANTUM,
- __TCA_FQ_CODEL_MAX
-};
-
-#define TCA_FQ_CODEL_MAX (__TCA_FQ_CODEL_MAX - 1)
-
/* ATM section */
enum {
@@ -501,6 +547,14 @@ enum {
TCA_NETEM_REORDER,
TCA_NETEM_CORRUPT,
TCA_NETEM_LOSS,
+ TCA_NETEM_RATE,
+ TCA_NETEM_ECN,
+ TCA_NETEM_RATE64,
+ TCA_NETEM_PAD,
+ TCA_NETEM_LATENCY64,
+ TCA_NETEM_JITTER64,
+ TCA_NETEM_SLOT,
+ TCA_NETEM_SLOT_DIST,
__TCA_NETEM_MAX,
};
@@ -531,6 +585,22 @@ struct tc_netem_corrupt {
__u32 correlation;
};
+struct tc_netem_rate {
+ __u32 rate; /* byte/s */
+ __s32 packet_overhead;
+ __u32 cell_size;
+ __s32 cell_overhead;
+};
+
+struct tc_netem_slot {
+ __s64 min_delay; /* nsec */
+ __s64 max_delay;
+ __s32 max_packets;
+ __s32 max_bytes;
+ __s64 dist_delay; /* nsec */
+ __s64 dist_jitter; /* nsec */
+};
+
enum {
NETEM_LOSS_UNSPEC,
NETEM_LOSS_GI, /* General Intuitive - 4 state model */
@@ -539,7 +609,7 @@ enum {
};
#define NETEM_LOSS_MAX (__NETEM_LOSS_MAX - 1)
-/* State transition probablities for 4 state model */
+/* State transition probabilities for 4 state model */
struct tc_netem_gimodel {
__u32 p13;
__u32 p31;
@@ -577,6 +647,30 @@ struct tc_drr_stats {
#define TC_QOPT_BITMASK 15
#define TC_QOPT_MAX_QUEUE 16
+enum {
+ TC_MQPRIO_HW_OFFLOAD_NONE, /* no offload requested */
+ TC_MQPRIO_HW_OFFLOAD_TCS, /* offload TCs, no queue counts */
+ __TC_MQPRIO_HW_OFFLOAD_MAX
+};
+
+#define TC_MQPRIO_HW_OFFLOAD_MAX (__TC_MQPRIO_HW_OFFLOAD_MAX - 1)
+
+enum {
+ TC_MQPRIO_MODE_DCB,
+ TC_MQPRIO_MODE_CHANNEL,
+ __TC_MQPRIO_MODE_MAX
+};
+
+#define __TC_MQPRIO_MODE_MAX (__TC_MQPRIO_MODE_MAX - 1)
+
+enum {
+ TC_MQPRIO_SHAPER_DCB,
+ TC_MQPRIO_SHAPER_BW_RATE, /* Add new shapers below */
+ __TC_MQPRIO_SHAPER_MAX
+};
+
+#define __TC_MQPRIO_SHAPER_MAX (__TC_MQPRIO_SHAPER_MAX - 1)
+
struct tc_mqprio_qopt {
__u8 num_tc;
__u8 prio_tc_map[TC_QOPT_BITMASK + 1];
@@ -585,6 +679,22 @@ struct tc_mqprio_qopt {
__u16 offset[TC_QOPT_MAX_QUEUE];
};
+#define TC_MQPRIO_F_MODE 0x1
+#define TC_MQPRIO_F_SHAPER 0x2
+#define TC_MQPRIO_F_MIN_RATE 0x4
+#define TC_MQPRIO_F_MAX_RATE 0x8
+
+enum {
+ TCA_MQPRIO_UNSPEC,
+ TCA_MQPRIO_MODE,
+ TCA_MQPRIO_SHAPER,
+ TCA_MQPRIO_MIN_RATE64,
+ TCA_MQPRIO_MAX_RATE64,
+ __TCA_MQPRIO_MAX,
+};
+
+#define TCA_MQPRIO_MAX (__TCA_MQPRIO_MAX - 1)
+
/* SFB */
enum {
@@ -639,4 +749,339 @@ struct tc_qfq_stats {
__u32 lmax;
};
+/* CODEL */
+
+enum {
+ TCA_CODEL_UNSPEC,
+ TCA_CODEL_TARGET,
+ TCA_CODEL_LIMIT,
+ TCA_CODEL_INTERVAL,
+ TCA_CODEL_ECN,
+ TCA_CODEL_CE_THRESHOLD,
+ __TCA_CODEL_MAX
+};
+
+#define TCA_CODEL_MAX (__TCA_CODEL_MAX - 1)
+
+struct tc_codel_xstats {
+ __u32 maxpacket; /* largest packet we've seen so far */
+ __u32 count; /* how many drops we've done since the last time we
+ * entered dropping state
+ */
+ __u32 lastcount; /* count at entry to dropping state */
+ __u32 ldelay; /* in-queue delay seen by most recently dequeued packet */
+ __s32 drop_next; /* time to drop next packet */
+ __u32 drop_overlimit; /* number of time max qdisc packet limit was hit */
+ __u32 ecn_mark; /* number of packets we ECN marked instead of dropped */
+ __u32 dropping; /* are we in dropping state ? */
+ __u32 ce_mark; /* number of CE marked packets because of ce_threshold */
+};
+
+/* FQ_CODEL */
+
+enum {
+ TCA_FQ_CODEL_UNSPEC,
+ TCA_FQ_CODEL_TARGET,
+ TCA_FQ_CODEL_LIMIT,
+ TCA_FQ_CODEL_INTERVAL,
+ TCA_FQ_CODEL_ECN,
+ TCA_FQ_CODEL_FLOWS,
+ TCA_FQ_CODEL_QUANTUM,
+ TCA_FQ_CODEL_CE_THRESHOLD,
+ TCA_FQ_CODEL_DROP_BATCH_SIZE,
+ TCA_FQ_CODEL_MEMORY_LIMIT,
+ __TCA_FQ_CODEL_MAX
+};
+
+#define TCA_FQ_CODEL_MAX (__TCA_FQ_CODEL_MAX - 1)
+
+enum {
+ TCA_FQ_CODEL_XSTATS_QDISC,
+ TCA_FQ_CODEL_XSTATS_CLASS,
+};
+
+struct tc_fq_codel_qd_stats {
+ __u32 maxpacket; /* largest packet we've seen so far */
+ __u32 drop_overlimit; /* number of time max qdisc
+ * packet limit was hit
+ */
+ __u32 ecn_mark; /* number of packets we ECN marked
+ * instead of being dropped
+ */
+ __u32 new_flow_count; /* number of time packets
+ * created a 'new flow'
+ */
+ __u32 new_flows_len; /* count of flows in new list */
+ __u32 old_flows_len; /* count of flows in old list */
+ __u32 ce_mark; /* packets above ce_threshold */
+ __u32 memory_usage; /* in bytes */
+ __u32 drop_overmemory;
+};
+
+struct tc_fq_codel_cl_stats {
+ __s32 deficit;
+ __u32 ldelay; /* in-queue delay seen by most recently
+ * dequeued packet
+ */
+ __u32 count;
+ __u32 lastcount;
+ __u32 dropping;
+ __s32 drop_next;
+};
+
+struct tc_fq_codel_xstats {
+ __u32 type;
+ union {
+ struct tc_fq_codel_qd_stats qdisc_stats;
+ struct tc_fq_codel_cl_stats class_stats;
+ };
+};
+
+/* FQ */
+
+enum {
+ TCA_FQ_UNSPEC,
+
+ TCA_FQ_PLIMIT, /* limit of total number of packets in queue */
+
+ TCA_FQ_FLOW_PLIMIT, /* limit of packets per flow */
+
+ TCA_FQ_QUANTUM, /* RR quantum */
+
+ TCA_FQ_INITIAL_QUANTUM, /* RR quantum for new flow */
+
+ TCA_FQ_RATE_ENABLE, /* enable/disable rate limiting */
+
+ TCA_FQ_FLOW_DEFAULT_RATE,/* obsolete, do not use */
+
+ TCA_FQ_FLOW_MAX_RATE, /* per flow max rate */
+
+ TCA_FQ_BUCKETS_LOG, /* log2(number of buckets) */
+
+ TCA_FQ_FLOW_REFILL_DELAY, /* flow credit refill delay in usec */
+
+ TCA_FQ_ORPHAN_MASK, /* mask applied to orphaned skb hashes */
+
+ TCA_FQ_LOW_RATE_THRESHOLD, /* per packet delay under this rate */
+
+ __TCA_FQ_MAX
+};
+
+#define TCA_FQ_MAX (__TCA_FQ_MAX - 1)
+
+struct tc_fq_qd_stats {
+ __u64 gc_flows;
+ __u64 highprio_packets;
+ __u64 tcp_retrans;
+ __u64 throttled;
+ __u64 flows_plimit;
+ __u64 pkts_too_long;
+ __u64 allocation_errors;
+ __s64 time_next_delayed_flow;
+ __u32 flows;
+ __u32 inactive_flows;
+ __u32 throttled_flows;
+ __u32 unthrottle_latency_ns;
+};
+
+/* Heavy-Hitter Filter */
+
+enum {
+ TCA_HHF_UNSPEC,
+ TCA_HHF_BACKLOG_LIMIT,
+ TCA_HHF_QUANTUM,
+ TCA_HHF_HH_FLOWS_LIMIT,
+ TCA_HHF_RESET_TIMEOUT,
+ TCA_HHF_ADMIT_BYTES,
+ TCA_HHF_EVICT_TIMEOUT,
+ TCA_HHF_NON_HH_WEIGHT,
+ __TCA_HHF_MAX
+};
+
+#define TCA_HHF_MAX (__TCA_HHF_MAX - 1)
+
+struct tc_hhf_xstats {
+ __u32 drop_overlimit; /* number of times max qdisc packet limit
+ * was hit
+ */
+ __u32 hh_overlimit; /* number of times max heavy-hitters was hit */
+ __u32 hh_tot_count; /* number of captured heavy-hitters so far */
+ __u32 hh_cur_count; /* number of current heavy-hitters */
+};
+
+/* PIE */
+enum {
+ TCA_PIE_UNSPEC,
+ TCA_PIE_TARGET,
+ TCA_PIE_LIMIT,
+ TCA_PIE_TUPDATE,
+ TCA_PIE_ALPHA,
+ TCA_PIE_BETA,
+ TCA_PIE_ECN,
+ TCA_PIE_BYTEMODE,
+ __TCA_PIE_MAX
+};
+#define TCA_PIE_MAX (__TCA_PIE_MAX - 1)
+
+struct tc_pie_xstats {
+ __u32 prob; /* current probability */
+ __u32 delay; /* current delay in ms */
+ __u32 avg_dq_rate; /* current average dq_rate in bits/pie_time */
+ __u32 packets_in; /* total number of packets enqueued */
+ __u32 dropped; /* packets dropped due to pie_action */
+ __u32 overlimit; /* dropped due to lack of space in queue */
+ __u32 maxq; /* maximum queue size */
+ __u32 ecn_mark; /* packets marked with ecn*/
+};
+
+/* CBS */
+struct tc_cbs_qopt {
+ __u8 offload;
+ __u8 _pad[3];
+ __s32 hicredit;
+ __s32 locredit;
+ __s32 idleslope;
+ __s32 sendslope;
+};
+
+enum {
+ TCA_CBS_UNSPEC,
+ TCA_CBS_PARMS,
+ __TCA_CBS_MAX,
+};
+
+#define TCA_CBS_MAX (__TCA_CBS_MAX - 1)
+
+
+/* ETF */
+struct tc_etf_qopt {
+ __s32 delta;
+ __s32 clockid;
+ __u32 flags;
+#define TC_ETF_DEADLINE_MODE_ON BIT(0)
+#define TC_ETF_OFFLOAD_ON BIT(1)
+};
+
+enum {
+ TCA_ETF_UNSPEC,
+ TCA_ETF_PARMS,
+ __TCA_ETF_MAX,
+};
+
+#define TCA_ETF_MAX (__TCA_ETF_MAX - 1)
+
+
+/* CAKE */
+enum {
+ TCA_CAKE_UNSPEC,
+ TCA_CAKE_PAD,
+ TCA_CAKE_BASE_RATE64,
+ TCA_CAKE_DIFFSERV_MODE,
+ TCA_CAKE_ATM,
+ TCA_CAKE_FLOW_MODE,
+ TCA_CAKE_OVERHEAD,
+ TCA_CAKE_RTT,
+ TCA_CAKE_TARGET,
+ TCA_CAKE_AUTORATE,
+ TCA_CAKE_MEMORY,
+ TCA_CAKE_NAT,
+ TCA_CAKE_RAW,
+ TCA_CAKE_WASH,
+ TCA_CAKE_MPU,
+ TCA_CAKE_INGRESS,
+ TCA_CAKE_ACK_FILTER,
+ TCA_CAKE_SPLIT_GSO,
+ __TCA_CAKE_MAX
+};
+#define TCA_CAKE_MAX (__TCA_CAKE_MAX - 1)
+
+enum {
+ __TCA_CAKE_STATS_INVALID,
+ TCA_CAKE_STATS_PAD,
+ TCA_CAKE_STATS_CAPACITY_ESTIMATE64,
+ TCA_CAKE_STATS_MEMORY_LIMIT,
+ TCA_CAKE_STATS_MEMORY_USED,
+ TCA_CAKE_STATS_AVG_NETOFF,
+ TCA_CAKE_STATS_MIN_NETLEN,
+ TCA_CAKE_STATS_MAX_NETLEN,
+ TCA_CAKE_STATS_MIN_ADJLEN,
+ TCA_CAKE_STATS_MAX_ADJLEN,
+ TCA_CAKE_STATS_TIN_STATS,
+ TCA_CAKE_STATS_DEFICIT,
+ TCA_CAKE_STATS_COBALT_COUNT,
+ TCA_CAKE_STATS_DROPPING,
+ TCA_CAKE_STATS_DROP_NEXT_US,
+ TCA_CAKE_STATS_P_DROP,
+ TCA_CAKE_STATS_BLUE_TIMER_US,
+ __TCA_CAKE_STATS_MAX
+};
+#define TCA_CAKE_STATS_MAX (__TCA_CAKE_STATS_MAX - 1)
+
+enum {
+ __TCA_CAKE_TIN_STATS_INVALID,
+ TCA_CAKE_TIN_STATS_PAD,
+ TCA_CAKE_TIN_STATS_SENT_PACKETS,
+ TCA_CAKE_TIN_STATS_SENT_BYTES64,
+ TCA_CAKE_TIN_STATS_DROPPED_PACKETS,
+ TCA_CAKE_TIN_STATS_DROPPED_BYTES64,
+ TCA_CAKE_TIN_STATS_ACKS_DROPPED_PACKETS,
+ TCA_CAKE_TIN_STATS_ACKS_DROPPED_BYTES64,
+ TCA_CAKE_TIN_STATS_ECN_MARKED_PACKETS,
+ TCA_CAKE_TIN_STATS_ECN_MARKED_BYTES64,
+ TCA_CAKE_TIN_STATS_BACKLOG_PACKETS,
+ TCA_CAKE_TIN_STATS_BACKLOG_BYTES,
+ TCA_CAKE_TIN_STATS_THRESHOLD_RATE64,
+ TCA_CAKE_TIN_STATS_TARGET_US,
+ TCA_CAKE_TIN_STATS_INTERVAL_US,
+ TCA_CAKE_TIN_STATS_WAY_INDIRECT_HITS,
+ TCA_CAKE_TIN_STATS_WAY_MISSES,
+ TCA_CAKE_TIN_STATS_WAY_COLLISIONS,
+ TCA_CAKE_TIN_STATS_PEAK_DELAY_US,
+ TCA_CAKE_TIN_STATS_AVG_DELAY_US,
+ TCA_CAKE_TIN_STATS_BASE_DELAY_US,
+ TCA_CAKE_TIN_STATS_SPARSE_FLOWS,
+ TCA_CAKE_TIN_STATS_BULK_FLOWS,
+ TCA_CAKE_TIN_STATS_UNRESPONSIVE_FLOWS,
+ TCA_CAKE_TIN_STATS_MAX_SKBLEN,
+ TCA_CAKE_TIN_STATS_FLOW_QUANTUM,
+ __TCA_CAKE_TIN_STATS_MAX
+};
+#define TCA_CAKE_TIN_STATS_MAX (__TCA_CAKE_TIN_STATS_MAX - 1)
+#define TC_CAKE_MAX_TINS (8)
+
+enum {
+ CAKE_FLOW_NONE = 0,
+ CAKE_FLOW_SRC_IP,
+ CAKE_FLOW_DST_IP,
+ CAKE_FLOW_HOSTS, /* = CAKE_FLOW_SRC_IP | CAKE_FLOW_DST_IP */
+ CAKE_FLOW_FLOWS,
+ CAKE_FLOW_DUAL_SRC, /* = CAKE_FLOW_SRC_IP | CAKE_FLOW_FLOWS */
+ CAKE_FLOW_DUAL_DST, /* = CAKE_FLOW_DST_IP | CAKE_FLOW_FLOWS */
+ CAKE_FLOW_TRIPLE, /* = CAKE_FLOW_HOSTS | CAKE_FLOW_FLOWS */
+ CAKE_FLOW_MAX,
+};
+
+enum {
+ CAKE_DIFFSERV_DIFFSERV3 = 0,
+ CAKE_DIFFSERV_DIFFSERV4,
+ CAKE_DIFFSERV_DIFFSERV8,
+ CAKE_DIFFSERV_BESTEFFORT,
+ CAKE_DIFFSERV_PRECEDENCE,
+ CAKE_DIFFSERV_MAX
+};
+
+enum {
+ CAKE_ACK_NONE = 0,
+ CAKE_ACK_FILTER,
+ CAKE_ACK_AGGRESSIVE,
+ CAKE_ACK_MAX
+};
+
+enum {
+ CAKE_ATM_NONE = 0,
+ CAKE_ATM_ATM,
+ CAKE_ATM_PTM,
+ CAKE_ATM_MAX
+};
+
#endif
diff --git a/include/linux-private/linux/rtnetlink.h b/include/linux-private/linux/rtnetlink.h
index 2363c18e..8c1d600b 100644
--- a/include/linux-private/linux/rtnetlink.h
+++ b/include/linux-private/linux/rtnetlink.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_RTNETLINK_H
#define __LINUX_RTNETLINK_H
@@ -120,6 +121,42 @@ enum {
RTM_SETDCB,
#define RTM_SETDCB RTM_SETDCB
+ RTM_NEWNETCONF = 80,
+#define RTM_NEWNETCONF RTM_NEWNETCONF
+ RTM_DELNETCONF,
+#define RTM_DELNETCONF RTM_DELNETCONF
+ RTM_GETNETCONF = 82,
+#define RTM_GETNETCONF RTM_GETNETCONF
+
+ RTM_NEWMDB = 84,
+#define RTM_NEWMDB RTM_NEWMDB
+ RTM_DELMDB = 85,
+#define RTM_DELMDB RTM_DELMDB
+ RTM_GETMDB = 86,
+#define RTM_GETMDB RTM_GETMDB
+
+ RTM_NEWNSID = 88,
+#define RTM_NEWNSID RTM_NEWNSID
+ RTM_DELNSID = 89,
+#define RTM_DELNSID RTM_DELNSID
+ RTM_GETNSID = 90,
+#define RTM_GETNSID RTM_GETNSID
+
+ RTM_NEWSTATS = 92,
+#define RTM_NEWSTATS RTM_NEWSTATS
+ RTM_GETSTATS = 94,
+#define RTM_GETSTATS RTM_GETSTATS
+
+ RTM_NEWCACHEREPORT = 96,
+#define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT
+
+ RTM_NEWCHAIN = 100,
+#define RTM_NEWCHAIN RTM_NEWCHAIN
+ RTM_DELCHAIN,
+#define RTM_DELCHAIN RTM_DELCHAIN
+ RTM_GETCHAIN,
+#define RTM_GETCHAIN RTM_GETCHAIN
+
__RTM_MAX,
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
};
@@ -141,7 +178,7 @@ struct rtattr {
/* Macros to handle rtattributes */
-#define RTA_ALIGNTO 4
+#define RTA_ALIGNTO 4U
#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
#define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \
(rta)->rta_len >= sizeof(struct rtattr) && \
@@ -222,6 +259,13 @@ enum {
#define RTPROT_XORP 14 /* XORP */
#define RTPROT_NTK 15 /* Netsukuku */
#define RTPROT_DHCP 16 /* DHCP client */
+#define RTPROT_MROUTED 17 /* Multicast daemon */
+#define RTPROT_BABEL 42 /* Babel daemon */
+#define RTPROT_BGP 186 /* BGP Routes */
+#define RTPROT_ISIS 187 /* ISIS Routes */
+#define RTPROT_OSPF 188 /* OSPF Routes */
+#define RTPROT_RIP 189 /* RIP Routes */
+#define RTPROT_EIGRP 192 /* EIGRP Routes */
/* rtm_scope
@@ -249,6 +293,8 @@ enum rt_scope_t {
#define RTM_F_CLONED 0x200 /* This route is cloned */
#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */
#define RTM_F_PREFIX 0x800 /* Prefix addresses */
+#define RTM_F_LOOKUP_TABLE 0x1000 /* set rtm_table to FIB lookup result */
+#define RTM_F_FIB_MATCH 0x2000 /* return full fib lookup match */
/* Reserved table identifiers */
@@ -283,6 +329,19 @@ enum rtattr_type_t {
RTA_MP_ALGO, /* no longer used */
RTA_TABLE,
RTA_MARK,
+ RTA_MFC_STATS,
+ RTA_VIA,
+ RTA_NEWDST,
+ RTA_PREF,
+ RTA_ENCAP_TYPE,
+ RTA_ENCAP,
+ RTA_EXPIRES,
+ RTA_PAD,
+ RTA_UID,
+ RTA_TTL_PROPAGATE,
+ RTA_IP_PROTO,
+ RTA_SPORT,
+ RTA_DPORT,
__RTA_MAX
};
@@ -312,6 +371,11 @@ struct rtnexthop {
#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */
#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */
#define RTNH_F_ONLINK 4 /* Gateway is forced on link */
+#define RTNH_F_OFFLOAD 8 /* offloaded route */
+#define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */
+#define RTNH_F_UNRESOLVED 32 /* The entry is unresolved (ipmr) */
+
+#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD)
/* Macros to handle hexthops */
@@ -324,6 +388,12 @@ struct rtnexthop {
#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len))
#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0)))
+/* RTA_VIA */
+struct rtvia {
+ __kernel_sa_family_t rtvia_family;
+ __u8 rtvia_addr[0];
+};
+
/* RTM_CACHEINFO */
struct rta_cacheinfo {
@@ -372,15 +442,24 @@ enum {
#define RTAX_RTO_MIN RTAX_RTO_MIN
RTAX_INITRWND,
#define RTAX_INITRWND RTAX_INITRWND
+ RTAX_QUICKACK,
+#define RTAX_QUICKACK RTAX_QUICKACK
+ RTAX_CC_ALGO,
+#define RTAX_CC_ALGO RTAX_CC_ALGO
+ RTAX_FASTOPEN_NO_COOKIE,
+#define RTAX_FASTOPEN_NO_COOKIE RTAX_FASTOPEN_NO_COOKIE
__RTAX_MAX
};
#define RTAX_MAX (__RTAX_MAX - 1)
-#define RTAX_FEATURE_ECN 0x00000001
-#define RTAX_FEATURE_SACK 0x00000002
-#define RTAX_FEATURE_TIMESTAMP 0x00000004
-#define RTAX_FEATURE_ALLFRAG 0x00000008
+#define RTAX_FEATURE_ECN (1 << 0)
+#define RTAX_FEATURE_SACK (1 << 1)
+#define RTAX_FEATURE_TIMESTAMP (1 << 2)
+#define RTAX_FEATURE_ALLFRAG (1 << 3)
+
+#define RTAX_FEATURE_MASK (RTAX_FEATURE_ECN | RTAX_FEATURE_SACK | \
+ RTAX_FEATURE_TIMESTAMP | RTAX_FEATURE_ALLFRAG)
struct rta_session {
__u8 proto;
@@ -403,6 +482,12 @@ struct rta_session {
} u;
};
+struct rta_mfc_stats {
+ __u64 mfcs_packets;
+ __u64 mfcs_bytes;
+ __u64 mfcs_wrong_if;
+};
+
/****
* General form of address family dependent message.
****/
@@ -471,9 +556,19 @@ struct tcmsg {
int tcm_ifindex;
__u32 tcm_handle;
__u32 tcm_parent;
+/* tcm_block_index is used instead of tcm_parent
+ * in case tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK
+ */
+#define tcm_block_index tcm_parent
__u32 tcm_info;
};
+/* For manipulation of filters in shared block, tcm_ifindex is set to
+ * TCM_IFINDEX_MAGIC_BLOCK, and tcm_parent is aliased to tcm_block_index
+ * which is the block index.
+ */
+#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU)
+
enum {
TCA_UNSPEC,
TCA_KIND,
@@ -484,6 +579,12 @@ enum {
TCA_FCNT,
TCA_STATS2,
TCA_STAB,
+ TCA_PAD,
+ TCA_DUMP_INVISIBLE,
+ TCA_CHAIN,
+ TCA_HW_OFFLOAD,
+ TCA_INGRESS_BLOCK,
+ TCA_EGRESS_BLOCK,
__TCA_MAX
};
@@ -516,7 +617,6 @@ enum {
#define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1)
-#ifndef __KERNEL__
/* RTnetlink multicast groups - backwards compatibility for userspace */
#define RTMGRP_LINK 1
#define RTMGRP_NOTIFY 2
@@ -537,7 +637,6 @@ enum {
#define RTMGRP_DECnet_ROUTE 0x4000
#define RTMGRP_IPV6_PREFIX 0x20000
-#endif
/* RTnetlink multicast groups */
enum rtnetlink_groups {
@@ -585,6 +684,24 @@ enum rtnetlink_groups {
#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR
RTNLGRP_PHONET_ROUTE,
#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE
+ RTNLGRP_DCB,
+#define RTNLGRP_DCB RTNLGRP_DCB
+ RTNLGRP_IPV4_NETCONF,
+#define RTNLGRP_IPV4_NETCONF RTNLGRP_IPV4_NETCONF
+ RTNLGRP_IPV6_NETCONF,
+#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF
+ RTNLGRP_MDB,
+#define RTNLGRP_MDB RTNLGRP_MDB
+ RTNLGRP_MPLS_ROUTE,
+#define RTNLGRP_MPLS_ROUTE RTNLGRP_MPLS_ROUTE
+ RTNLGRP_NSID,
+#define RTNLGRP_NSID RTNLGRP_NSID
+ RTNLGRP_MPLS_NETCONF,
+#define RTNLGRP_MPLS_NETCONF RTNLGRP_MPLS_NETCONF
+ RTNLGRP_IPV4_MROUTE_R,
+#define RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV4_MROUTE_R
+ RTNLGRP_IPV6_MROUTE_R,
+#define RTNLGRP_IPV6_MROUTE_R RTNLGRP_IPV6_MROUTE_R
__RTNLGRP_MAX
};
#define RTNLGRP_MAX (__RTNLGRP_MAX - 1)
@@ -595,11 +712,38 @@ struct tcamsg {
unsigned char tca__pad1;
unsigned short tca__pad2;
};
+
+enum {
+ TCA_ROOT_UNSPEC,
+ TCA_ROOT_TAB,
+#define TCA_ACT_TAB TCA_ROOT_TAB
+#define TCAA_MAX TCA_ROOT_TAB
+ TCA_ROOT_FLAGS,
+ TCA_ROOT_COUNT,
+ TCA_ROOT_TIME_DELTA, /* in msecs */
+ __TCA_ROOT_MAX,
+#define TCA_ROOT_MAX (__TCA_ROOT_MAX - 1)
+};
+
#define TA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg))))
#define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg))
-#define TCA_ACT_TAB 1 /* attr type must be >=1 */
-#define TCAA_MAX 1
+/* tcamsg flags stored in attribute TCA_ROOT_FLAGS
+ *
+ * TCA_FLAG_LARGE_DUMP_ON user->kernel to request for larger than TCA_ACT_MAX_PRIO
+ * actions in a dump. All dump responses will contain the number of actions
+ * being dumped stored in for user app's consumption in TCA_ROOT_COUNT
+ *
+ */
+#define TCA_FLAG_LARGE_DUMP_ON (1 << 0)
+
+/* New extended info filters for IFLA_EXT_MASK */
+#define RTEXT_FILTER_VF (1 << 0)
+#define RTEXT_FILTER_BRVLAN (1 << 1)
+#define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2)
+#define RTEXT_FILTER_SKIP_STATS (1 << 3)
/* End of information exported to user level */
-#endif /* __LINUX_RTNETLINK_H */
+
+
+#endif /* __LINUX_RTNETLINK_H */
diff --git a/include/linux-private/linux/snmp.h b/include/linux-private/linux/snmp.h
index 1bdb4a39..abae27c3 100644
--- a/include/linux-private/linux/snmp.h
+++ b/include/linux-private/linux/snmp.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Definitions for MIBs
*
@@ -55,6 +56,7 @@ enum
IPSTATS_MIB_ECT1PKTS, /* InECT1Pkts */
IPSTATS_MIB_ECT0PKTS, /* InECT0Pkts */
IPSTATS_MIB_CEPKTS, /* InCEPkts */
+ IPSTATS_MIB_REASM_OVERLAPS, /* ReasmOverlaps */
__IPSTATS_MIB_MAX
};
@@ -156,6 +158,7 @@ enum
UDP_MIB_RCVBUFERRORS, /* RcvbufErrors */
UDP_MIB_SNDBUFERRORS, /* SndbufErrors */
UDP_MIB_CSUMERRORS, /* InCsumErrors */
+ UDP_MIB_IGNOREDMULTI, /* IgnoredMulti */
__UDP_MIB_MAX
};
@@ -176,7 +179,6 @@ enum
LINUX_MIB_TIMEWAITED, /* TimeWaited */
LINUX_MIB_TIMEWAITRECYCLED, /* TimeWaitRecycled */
LINUX_MIB_TIMEWAITKILLED, /* TimeWaitKilled */
- LINUX_MIB_PAWSPASSIVEREJECTED, /* PAWSPassiveRejected */
LINUX_MIB_PAWSACTIVEREJECTED, /* PAWSActiveRejected */
LINUX_MIB_PAWSESTABREJECTED, /* PAWSEstabRejected */
LINUX_MIB_DELAYEDACKS, /* DelayedACKs */
@@ -184,18 +186,12 @@ enum
LINUX_MIB_DELAYEDACKLOST, /* DelayedACKLost */
LINUX_MIB_LISTENOVERFLOWS, /* ListenOverflows */
LINUX_MIB_LISTENDROPS, /* ListenDrops */
- LINUX_MIB_TCPPREQUEUED, /* TCPPrequeued */
- LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG, /* TCPDirectCopyFromBacklog */
- LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, /* TCPDirectCopyFromPrequeue */
- LINUX_MIB_TCPPREQUEUEDROPPED, /* TCPPrequeueDropped */
LINUX_MIB_TCPHPHITS, /* TCPHPHits */
- LINUX_MIB_TCPHPHITSTOUSER, /* TCPHPHitsToUser */
LINUX_MIB_TCPPUREACKS, /* TCPPureAcks */
LINUX_MIB_TCPHPACKS, /* TCPHPAcks */
LINUX_MIB_TCPRENORECOVERY, /* TCPRenoRecovery */
LINUX_MIB_TCPSACKRECOVERY, /* TCPSackRecovery */
LINUX_MIB_TCPSACKRENEGING, /* TCPSACKReneging */
- LINUX_MIB_TCPFACKREORDER, /* TCPFACKReorder */
LINUX_MIB_TCPSACKREORDER, /* TCPSACKReorder */
LINUX_MIB_TCPRENOREORDER, /* TCPRenoReorder */
LINUX_MIB_TCPTSREORDER, /* TCPTSReorder */
@@ -208,14 +204,12 @@ enum
LINUX_MIB_TCPSACKFAILURES, /* TCPSackFailures */
LINUX_MIB_TCPLOSSFAILURES, /* TCPLossFailures */
LINUX_MIB_TCPFASTRETRANS, /* TCPFastRetrans */
- LINUX_MIB_TCPFORWARDRETRANS, /* TCPForwardRetrans */
LINUX_MIB_TCPSLOWSTARTRETRANS, /* TCPSlowStartRetrans */
LINUX_MIB_TCPTIMEOUTS, /* TCPTimeouts */
LINUX_MIB_TCPLOSSPROBES, /* TCPLossProbes */
LINUX_MIB_TCPLOSSPROBERECOVERY, /* TCPLossProbeRecovery */
LINUX_MIB_TCPRENORECOVERYFAIL, /* TCPRenoRecoveryFail */
LINUX_MIB_TCPSACKRECOVERYFAIL, /* TCPSackRecoveryFail */
- LINUX_MIB_TCPSCHEDULERFAILED, /* TCPSchedulerFailed */
LINUX_MIB_TCPRCVCOLLAPSED, /* TCPRcvCollapsed */
LINUX_MIB_TCPDSACKOLDSENT, /* TCPDSACKOldSent */
LINUX_MIB_TCPDSACKOFOSENT, /* TCPDSACKOfoSent */
@@ -228,16 +222,19 @@ enum
LINUX_MIB_TCPABORTONLINGER, /* TCPAbortOnLinger */
LINUX_MIB_TCPABORTFAILED, /* TCPAbortFailed */
LINUX_MIB_TCPMEMORYPRESSURES, /* TCPMemoryPressures */
+ LINUX_MIB_TCPMEMORYPRESSURESCHRONO, /* TCPMemoryPressuresChrono */
LINUX_MIB_TCPSACKDISCARD, /* TCPSACKDiscard */
LINUX_MIB_TCPDSACKIGNOREDOLD, /* TCPSACKIgnoredOld */
LINUX_MIB_TCPDSACKIGNOREDNOUNDO, /* TCPSACKIgnoredNoUndo */
LINUX_MIB_TCPSPURIOUSRTOS, /* TCPSpuriousRTOs */
LINUX_MIB_TCPMD5NOTFOUND, /* TCPMD5NotFound */
LINUX_MIB_TCPMD5UNEXPECTED, /* TCPMD5Unexpected */
+ LINUX_MIB_TCPMD5FAILURE, /* TCPMD5Failure */
LINUX_MIB_SACKSHIFTED,
LINUX_MIB_SACKMERGED,
LINUX_MIB_SACKSHIFTFALLBACK,
LINUX_MIB_TCPBACKLOGDROP,
+ LINUX_MIB_PFMEMALLOCDROP,
LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */
LINUX_MIB_TCPDEFERACCEPTDROP,
LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
@@ -252,12 +249,40 @@ enum
LINUX_MIB_TCPCHALLENGEACK, /* TCPChallengeACK */
LINUX_MIB_TCPSYNCHALLENGE, /* TCPSYNChallenge */
LINUX_MIB_TCPFASTOPENACTIVE, /* TCPFastOpenActive */
+ LINUX_MIB_TCPFASTOPENACTIVEFAIL, /* TCPFastOpenActiveFail */
LINUX_MIB_TCPFASTOPENPASSIVE, /* TCPFastOpenPassive*/
LINUX_MIB_TCPFASTOPENPASSIVEFAIL, /* TCPFastOpenPassiveFail */
LINUX_MIB_TCPFASTOPENLISTENOVERFLOW, /* TCPFastOpenListenOverflow */
LINUX_MIB_TCPFASTOPENCOOKIEREQD, /* TCPFastOpenCookieReqd */
+ LINUX_MIB_TCPFASTOPENBLACKHOLE, /* TCPFastOpenBlackholeDetect */
LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES, /* TCPSpuriousRtxHostQueues */
LINUX_MIB_BUSYPOLLRXPACKETS, /* BusyPollRxPackets */
+ LINUX_MIB_TCPAUTOCORKING, /* TCPAutoCorking */
+ LINUX_MIB_TCPFROMZEROWINDOWADV, /* TCPFromZeroWindowAdv */
+ LINUX_MIB_TCPTOZEROWINDOWADV, /* TCPToZeroWindowAdv */
+ LINUX_MIB_TCPWANTZEROWINDOWADV, /* TCPWantZeroWindowAdv */
+ LINUX_MIB_TCPSYNRETRANS, /* TCPSynRetrans */
+ LINUX_MIB_TCPORIGDATASENT, /* TCPOrigDataSent */
+ LINUX_MIB_TCPHYSTARTTRAINDETECT, /* TCPHystartTrainDetect */
+ LINUX_MIB_TCPHYSTARTTRAINCWND, /* TCPHystartTrainCwnd */
+ LINUX_MIB_TCPHYSTARTDELAYDETECT, /* TCPHystartDelayDetect */
+ LINUX_MIB_TCPHYSTARTDELAYCWND, /* TCPHystartDelayCwnd */
+ LINUX_MIB_TCPACKSKIPPEDSYNRECV, /* TCPACKSkippedSynRecv */
+ LINUX_MIB_TCPACKSKIPPEDPAWS, /* TCPACKSkippedPAWS */
+ LINUX_MIB_TCPACKSKIPPEDSEQ, /* TCPACKSkippedSeq */
+ LINUX_MIB_TCPACKSKIPPEDFINWAIT2, /* TCPACKSkippedFinWait2 */
+ LINUX_MIB_TCPACKSKIPPEDTIMEWAIT, /* TCPACKSkippedTimeWait */
+ LINUX_MIB_TCPACKSKIPPEDCHALLENGE, /* TCPACKSkippedChallenge */
+ LINUX_MIB_TCPWINPROBE, /* TCPWinProbe */
+ LINUX_MIB_TCPKEEPALIVE, /* TCPKeepAlive */
+ LINUX_MIB_TCPMTUPFAIL, /* TCPMTUPFail */
+ LINUX_MIB_TCPMTUPSUCCESS, /* TCPMTUPSuccess */
+ LINUX_MIB_TCPDELIVERED, /* TCPDelivered */
+ LINUX_MIB_TCPDELIVEREDCE, /* TCPDeliveredCE */
+ LINUX_MIB_TCPACKCOMPRESSED, /* TCPAckCompressed */
+ LINUX_MIB_TCPZEROWINDOWDROP, /* TCPZeroWindowDrop */
+ LINUX_MIB_TCPRCVQDROP, /* TCPRcvQDrop */
+ LINUX_MIB_TCPWQUEUETOOBIG, /* TCPWqueueTooBig */
__LINUX_MIB_MAX
};
diff --git a/include/linux-private/linux/sock_diag.h b/include/linux-private/linux/sock_diag.h
new file mode 100644
index 00000000..a69cf20f
--- /dev/null
+++ b/include/linux-private/linux/sock_diag.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __SOCK_DIAG_H__
+#define __SOCK_DIAG_H__
+
+#include <linux/types.h>
+
+#define SOCK_DIAG_BY_FAMILY 20
+#define SOCK_DESTROY 21
+
+struct sock_diag_req {
+ __u8 sdiag_family;
+ __u8 sdiag_protocol;
+};
+
+enum {
+ SK_MEMINFO_RMEM_ALLOC,
+ SK_MEMINFO_RCVBUF,
+ SK_MEMINFO_WMEM_ALLOC,
+ SK_MEMINFO_SNDBUF,
+ SK_MEMINFO_FWD_ALLOC,
+ SK_MEMINFO_WMEM_QUEUED,
+ SK_MEMINFO_OPTMEM,
+ SK_MEMINFO_BACKLOG,
+ SK_MEMINFO_DROPS,
+
+ SK_MEMINFO_VARS,
+};
+
+enum sknetlink_groups {
+ SKNLGRP_NONE,
+ SKNLGRP_INET_TCP_DESTROY,
+ SKNLGRP_INET_UDP_DESTROY,
+ SKNLGRP_INET6_TCP_DESTROY,
+ SKNLGRP_INET6_UDP_DESTROY,
+ __SKNLGRP_MAX,
+};
+#define SKNLGRP_MAX (__SKNLGRP_MAX - 1)
+
+#endif /* __SOCK_DIAG_H__ */
diff --git a/include/linux-private/linux/socket.h b/include/linux-private/linux/socket.h
new file mode 100644
index 00000000..268b9482
--- /dev/null
+++ b/include/linux-private/linux/socket.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_SOCKET_H
+#define _LINUX_SOCKET_H
+
+/*
+ * Desired design of maximum size and alignment (see RFC2553)
+ */
+#define _K_SS_MAXSIZE 128 /* Implementation specific max size */
+#define _K_SS_ALIGNSIZE (__alignof__ (struct sockaddr *))
+ /* Implementation specific desired alignment */
+
+typedef unsigned short __kernel_sa_family_t;
+
+struct __kernel_sockaddr_storage {
+ __kernel_sa_family_t ss_family; /* address family */
+ /* Following field(s) are implementation specific */
+ char __data[_K_SS_MAXSIZE - sizeof(unsigned short)];
+ /* space to achieve desired size, */
+ /* _SS_MAXSIZE value minus size of ss_family */
+} __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */
+
+#endif /* _LINUX_SOCKET_H */
diff --git a/include/linux-private/linux/tc_act/tc_gact.h b/include/linux-private/linux/tc_act/tc_gact.h
new file mode 100644
index 00000000..94273c3b
--- /dev/null
+++ b/include/linux-private/linux/tc_act/tc_gact.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_TC_GACT_H
+#define __LINUX_TC_GACT_H
+
+#include <linux/types.h>
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_GACT 5
+struct tc_gact {
+ tc_gen;
+
+};
+
+struct tc_gact_p {
+#define PGACT_NONE 0
+#define PGACT_NETRAND 1
+#define PGACT_DETERM 2
+#define MAX_RAND (PGACT_DETERM + 1 )
+ __u16 ptype;
+ __u16 pval;
+ int paction;
+};
+
+enum {
+ TCA_GACT_UNSPEC,
+ TCA_GACT_TM,
+ TCA_GACT_PARMS,
+ TCA_GACT_PROB,
+ TCA_GACT_PAD,
+ __TCA_GACT_MAX
+};
+#define TCA_GACT_MAX (__TCA_GACT_MAX - 1)
+
+#endif
diff --git a/include/linux-private/linux/tc_act/tc_mirred.h b/include/linux-private/linux/tc_act/tc_mirred.h
index 7561750e..5dd671cf 100644
--- a/include/linux-private/linux/tc_act/tc_mirred.h
+++ b/include/linux-private/linux/tc_act/tc_mirred.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_TC_MIR_H
#define __LINUX_TC_MIR_H
@@ -9,19 +10,20 @@
#define TCA_EGRESS_MIRROR 2 /* mirror packet to EGRESS */
#define TCA_INGRESS_REDIR 3 /* packet redirect to INGRESS*/
#define TCA_INGRESS_MIRROR 4 /* mirror packet to INGRESS */
-
+
struct tc_mirred {
tc_gen;
int eaction; /* one of IN/EGRESS_MIRROR/REDIR */
__u32 ifindex; /* ifindex of egress port */
};
-
+
enum {
TCA_MIRRED_UNSPEC,
TCA_MIRRED_TM,
TCA_MIRRED_PARMS,
+ TCA_MIRRED_PAD,
__TCA_MIRRED_MAX
};
#define TCA_MIRRED_MAX (__TCA_MIRRED_MAX - 1)
-
+
#endif
diff --git a/include/linux-private/linux/tc_act/tc_skbedit.h b/include/linux-private/linux/tc_act/tc_skbedit.h
new file mode 100644
index 00000000..6de6071e
--- /dev/null
+++ b/include/linux-private/linux/tc_act/tc_skbedit.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * Copyright (c) 2008, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Author: Alexander Duyck <alexander.h.duyck@intel.com>
+ */
+
+#ifndef __LINUX_TC_SKBEDIT_H
+#define __LINUX_TC_SKBEDIT_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_SKBEDIT 11
+
+#define SKBEDIT_F_PRIORITY 0x1
+#define SKBEDIT_F_QUEUE_MAPPING 0x2
+#define SKBEDIT_F_MARK 0x4
+#define SKBEDIT_F_PTYPE 0x8
+#define SKBEDIT_F_MASK 0x10
+#define SKBEDIT_F_INHERITDSFIELD 0x20
+
+struct tc_skbedit {
+ tc_gen;
+};
+
+enum {
+ TCA_SKBEDIT_UNSPEC,
+ TCA_SKBEDIT_TM,
+ TCA_SKBEDIT_PARMS,
+ TCA_SKBEDIT_PRIORITY,
+ TCA_SKBEDIT_QUEUE_MAPPING,
+ TCA_SKBEDIT_MARK,
+ TCA_SKBEDIT_PAD,
+ TCA_SKBEDIT_PTYPE,
+ TCA_SKBEDIT_MASK,
+ TCA_SKBEDIT_FLAGS,
+ __TCA_SKBEDIT_MAX
+};
+#define TCA_SKBEDIT_MAX (__TCA_SKBEDIT_MAX - 1)
+
+#endif
diff --git a/include/linux-private/linux/tc_act/tc_vlan.h b/include/linux-private/linux/tc_act/tc_vlan.h
new file mode 100644
index 00000000..0d7b5fd6
--- /dev/null
+++ b/include/linux-private/linux/tc_act/tc_vlan.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Copyright (c) 2014 Jiri Pirko <jiri@resnulli.us>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __LINUX_TC_VLAN_H
+#define __LINUX_TC_VLAN_H
+
+#include <linux/pkt_cls.h>
+
+#define TCA_ACT_VLAN 12
+
+#define TCA_VLAN_ACT_POP 1
+#define TCA_VLAN_ACT_PUSH 2
+#define TCA_VLAN_ACT_MODIFY 3
+
+struct tc_vlan {
+ tc_gen;
+ int v_action;
+};
+
+enum {
+ TCA_VLAN_UNSPEC,
+ TCA_VLAN_TM,
+ TCA_VLAN_PARMS,
+ TCA_VLAN_PUSH_VLAN_ID,
+ TCA_VLAN_PUSH_VLAN_PROTOCOL,
+ TCA_VLAN_PAD,
+ TCA_VLAN_PUSH_VLAN_PRIORITY,
+ __TCA_VLAN_MAX,
+};
+#define TCA_VLAN_MAX (__TCA_VLAN_MAX - 1)
+
+#endif
diff --git a/include/linux-private/linux/tc_ematch/tc_em_meta.h b/include/linux-private/linux/tc_ematch/tc_em_meta.h
index fe815e26..cf30b5bc 100644
--- a/include/linux-private/linux/tc_ematch/tc_em_meta.h
+++ b/include/linux-private/linux/tc_ematch/tc_em_meta.h
@@ -1,6 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef __LINUX_TC_EM_META_H
#define __LINUX_TC_EM_META_H
+#include <linux/types.h>
+#include <linux/pkt_cls.h>
+
enum {
TCA_EM_META_UNSPEC,
TCA_EM_META_HDR,
@@ -64,7 +68,7 @@ enum {
TCF_META_ID_SK_FORWARD_ALLOCS,
TCF_META_ID_SK_SNDBUF,
TCF_META_ID_SK_ALLOCS,
- TCF_META_ID_SK_ROUTE_CAPS,
+ __TCF_META_ID_SK_ROUTE_CAPS, /* unimplemented but in ABI already */
TCF_META_ID_SK_HASH,
TCF_META_ID_SK_LINGERTIME,
TCF_META_ID_SK_ACK_BACKLOG,
diff --git a/include/linux-private/linux/veth.h b/include/linux-private/linux/veth.h
new file mode 100644
index 00000000..52b58e58
--- /dev/null
+++ b/include/linux-private/linux/veth.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __NET_VETH_H_
+#define __NET_VETH_H_
+
+enum {
+ VETH_INFO_UNSPEC,
+ VETH_INFO_PEER,
+
+ __VETH_INFO_MAX
+#define VETH_INFO_MAX (__VETH_INFO_MAX - 1)
+};
+
+#endif
diff --git a/include/linux-private/linux/xfrm.h b/include/linux-private/linux/xfrm.h
new file mode 100644
index 00000000..5cdda9d3
--- /dev/null
+++ b/include/linux-private/linux/xfrm.h
@@ -0,0 +1,540 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _LINUX_XFRM_H
+#define _LINUX_XFRM_H
+
+#include <linux/in6.h>
+#include <linux/types.h>
+
+/* All of the structures in this file may not change size as they are
+ * passed into the kernel from userspace via netlink sockets.
+ */
+
+/* Structure to encapsulate addresses. I do not want to use
+ * "standard" structure. My apologies.
+ */
+typedef union {
+ __be32 a4;
+ __be32 a6[4];
+ struct in6_addr in6;
+} xfrm_address_t;
+
+/* Ident of a specific xfrm_state. It is used on input to lookup
+ * the state by (spi,daddr,ah/esp) or to store information about
+ * spi, protocol and tunnel address on output.
+ */
+struct xfrm_id {
+ xfrm_address_t daddr;
+ __be32 spi;
+ __u8 proto;
+};
+
+struct xfrm_sec_ctx {
+ __u8 ctx_doi;
+ __u8 ctx_alg;
+ __u16 ctx_len;
+ __u32 ctx_sid;
+ char ctx_str[0];
+};
+
+/* Security Context Domains of Interpretation */
+#define XFRM_SC_DOI_RESERVED 0
+#define XFRM_SC_DOI_LSM 1
+
+/* Security Context Algorithms */
+#define XFRM_SC_ALG_RESERVED 0
+#define XFRM_SC_ALG_SELINUX 1
+
+/* Selector, used as selector both on policy rules (SPD) and SAs. */
+
+struct xfrm_selector {
+ xfrm_address_t daddr;
+ xfrm_address_t saddr;
+ __be16 dport;
+ __be16 dport_mask;
+ __be16 sport;
+ __be16 sport_mask;
+ __u16 family;
+ __u8 prefixlen_d;
+ __u8 prefixlen_s;
+ __u8 proto;
+ int ifindex;
+ __kernel_uid32_t user;
+};
+
+#define XFRM_INF (~(__u64)0)
+
+struct xfrm_lifetime_cfg {
+ __u64 soft_byte_limit;
+ __u64 hard_byte_limit;
+ __u64 soft_packet_limit;
+ __u64 hard_packet_limit;
+ __u64 soft_add_expires_seconds;
+ __u64 hard_add_expires_seconds;
+ __u64 soft_use_expires_seconds;
+ __u64 hard_use_expires_seconds;
+};
+
+struct xfrm_lifetime_cur {
+ __u64 bytes;
+ __u64 packets;
+ __u64 add_time;
+ __u64 use_time;
+};
+
+struct xfrm_replay_state {
+ __u32 oseq;
+ __u32 seq;
+ __u32 bitmap;
+};
+
+#define XFRMA_REPLAY_ESN_MAX 4096
+
+struct xfrm_replay_state_esn {
+ unsigned int bmp_len;
+ __u32 oseq;
+ __u32 seq;
+ __u32 oseq_hi;
+ __u32 seq_hi;
+ __u32 replay_window;
+ __u32 bmp[0];
+};
+
+struct xfrm_algo {
+ char alg_name[64];
+ unsigned int alg_key_len; /* in bits */
+ char alg_key[0];
+};
+
+struct xfrm_algo_auth {
+ char alg_name[64];
+ unsigned int alg_key_len; /* in bits */
+ unsigned int alg_trunc_len; /* in bits */
+ char alg_key[0];
+};
+
+struct xfrm_algo_aead {
+ char alg_name[64];
+ unsigned int alg_key_len; /* in bits */
+ unsigned int alg_icv_len; /* in bits */
+ char alg_key[0];
+};
+
+struct xfrm_stats {
+ __u32 replay_window;
+ __u32 replay;
+ __u32 integrity_failed;
+};
+
+enum {
+ XFRM_POLICY_TYPE_MAIN = 0,
+ XFRM_POLICY_TYPE_SUB = 1,
+ XFRM_POLICY_TYPE_MAX = 2,
+ XFRM_POLICY_TYPE_ANY = 255
+};
+
+enum {
+ XFRM_POLICY_IN = 0,
+ XFRM_POLICY_OUT = 1,
+ XFRM_POLICY_FWD = 2,
+ XFRM_POLICY_MASK = 3,
+ XFRM_POLICY_MAX = 3
+};
+
+enum {
+ XFRM_SHARE_ANY, /* No limitations */
+ XFRM_SHARE_SESSION, /* For this session only */
+ XFRM_SHARE_USER, /* For this user only */
+ XFRM_SHARE_UNIQUE /* Use once */
+};
+
+#define XFRM_MODE_TRANSPORT 0
+#define XFRM_MODE_TUNNEL 1
+#define XFRM_MODE_ROUTEOPTIMIZATION 2
+#define XFRM_MODE_IN_TRIGGER 3
+#define XFRM_MODE_BEET 4
+#define XFRM_MODE_MAX 5
+
+/* Netlink configuration messages. */
+enum {
+ XFRM_MSG_BASE = 0x10,
+
+ XFRM_MSG_NEWSA = 0x10,
+#define XFRM_MSG_NEWSA XFRM_MSG_NEWSA
+ XFRM_MSG_DELSA,
+#define XFRM_MSG_DELSA XFRM_MSG_DELSA
+ XFRM_MSG_GETSA,
+#define XFRM_MSG_GETSA XFRM_MSG_GETSA
+
+ XFRM_MSG_NEWPOLICY,
+#define XFRM_MSG_NEWPOLICY XFRM_MSG_NEWPOLICY
+ XFRM_MSG_DELPOLICY,
+#define XFRM_MSG_DELPOLICY XFRM_MSG_DELPOLICY
+ XFRM_MSG_GETPOLICY,
+#define XFRM_MSG_GETPOLICY XFRM_MSG_GETPOLICY
+
+ XFRM_MSG_ALLOCSPI,
+#define XFRM_MSG_ALLOCSPI XFRM_MSG_ALLOCSPI
+ XFRM_MSG_ACQUIRE,
+#define XFRM_MSG_ACQUIRE XFRM_MSG_ACQUIRE
+ XFRM_MSG_EXPIRE,
+#define XFRM_MSG_EXPIRE XFRM_MSG_EXPIRE
+
+ XFRM_MSG_UPDPOLICY,
+#define XFRM_MSG_UPDPOLICY XFRM_MSG_UPDPOLICY
+ XFRM_MSG_UPDSA,
+#define XFRM_MSG_UPDSA XFRM_MSG_UPDSA
+
+ XFRM_MSG_POLEXPIRE,
+#define XFRM_MSG_POLEXPIRE XFRM_MSG_POLEXPIRE
+
+ XFRM_MSG_FLUSHSA,
+#define XFRM_MSG_FLUSHSA XFRM_MSG_FLUSHSA
+ XFRM_MSG_FLUSHPOLICY,
+#define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY
+
+ XFRM_MSG_NEWAE,
+#define XFRM_MSG_NEWAE XFRM_MSG_NEWAE
+ XFRM_MSG_GETAE,
+#define XFRM_MSG_GETAE XFRM_MSG_GETAE
+
+ XFRM_MSG_REPORT,
+#define XFRM_MSG_REPORT XFRM_MSG_REPORT
+
+ XFRM_MSG_MIGRATE,
+#define XFRM_MSG_MIGRATE XFRM_MSG_MIGRATE
+
+ XFRM_MSG_NEWSADINFO,
+#define XFRM_MSG_NEWSADINFO XFRM_MSG_NEWSADINFO
+ XFRM_MSG_GETSADINFO,
+#define XFRM_MSG_GETSADINFO XFRM_MSG_GETSADINFO
+
+ XFRM_MSG_NEWSPDINFO,
+#define XFRM_MSG_NEWSPDINFO XFRM_MSG_NEWSPDINFO
+ XFRM_MSG_GETSPDINFO,
+#define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO
+
+ XFRM_MSG_MAPPING,
+#define XFRM_MSG_MAPPING XFRM_MSG_MAPPING
+ __XFRM_MSG_MAX
+};
+#define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1)
+
+#define XFRM_NR_MSGTYPES (XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)
+
+/*
+ * Generic LSM security context for comunicating to user space
+ * NOTE: Same format as sadb_x_sec_ctx
+ */
+struct xfrm_user_sec_ctx {
+ __u16 len;
+ __u16 exttype;
+ __u8 ctx_alg; /* LSMs: e.g., selinux == 1 */
+ __u8 ctx_doi;
+ __u16 ctx_len;
+};
+
+struct xfrm_user_tmpl {
+ struct xfrm_id id;
+ __u16 family;
+ xfrm_address_t saddr;
+ __u32 reqid;
+ __u8 mode;
+ __u8 share;
+ __u8 optional;
+ __u32 aalgos;
+ __u32 ealgos;
+ __u32 calgos;
+};
+
+struct xfrm_encap_tmpl {
+ __u16 encap_type;
+ __be16 encap_sport;
+ __be16 encap_dport;
+ xfrm_address_t encap_oa;
+};
+
+/* AEVENT flags */
+enum xfrm_ae_ftype_t {
+ XFRM_AE_UNSPEC,
+ XFRM_AE_RTHR=1, /* replay threshold*/
+ XFRM_AE_RVAL=2, /* replay value */
+ XFRM_AE_LVAL=4, /* lifetime value */
+ XFRM_AE_ETHR=8, /* expiry timer threshold */
+ XFRM_AE_CR=16, /* Event cause is replay update */
+ XFRM_AE_CE=32, /* Event cause is timer expiry */
+ XFRM_AE_CU=64, /* Event cause is policy update */
+ __XFRM_AE_MAX
+
+#define XFRM_AE_MAX (__XFRM_AE_MAX - 1)
+};
+
+struct xfrm_userpolicy_type {
+ __u8 type;
+ __u16 reserved1;
+ __u8 reserved2;
+};
+
+/* Netlink message attributes. */
+enum xfrm_attr_type_t {
+ XFRMA_UNSPEC,
+ XFRMA_ALG_AUTH, /* struct xfrm_algo */
+ XFRMA_ALG_CRYPT, /* struct xfrm_algo */
+ XFRMA_ALG_COMP, /* struct xfrm_algo */
+ XFRMA_ENCAP, /* struct xfrm_algo + struct xfrm_encap_tmpl */
+ XFRMA_TMPL, /* 1 or more struct xfrm_user_tmpl */
+ XFRMA_SA, /* struct xfrm_usersa_info */
+ XFRMA_POLICY, /*struct xfrm_userpolicy_info */
+ XFRMA_SEC_CTX, /* struct xfrm_sec_ctx */
+ XFRMA_LTIME_VAL,
+ XFRMA_REPLAY_VAL,
+ XFRMA_REPLAY_THRESH,
+ XFRMA_ETIMER_THRESH,
+ XFRMA_SRCADDR, /* xfrm_address_t */
+ XFRMA_COADDR, /* xfrm_address_t */
+ XFRMA_LASTUSED, /* unsigned long */
+ XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */
+ XFRMA_MIGRATE,
+ XFRMA_ALG_AEAD, /* struct xfrm_algo_aead */
+ XFRMA_KMADDRESS, /* struct xfrm_user_kmaddress */
+ XFRMA_ALG_AUTH_TRUNC, /* struct xfrm_algo_auth */
+ XFRMA_MARK, /* struct xfrm_mark */
+ XFRMA_TFCPAD, /* __u32 */
+ XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_state_esn */
+ XFRMA_SA_EXTRA_FLAGS, /* __u32 */
+ XFRMA_PROTO, /* __u8 */
+ XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */
+ XFRMA_PAD,
+ XFRMA_OFFLOAD_DEV, /* struct xfrm_state_offload */
+ XFRMA_SET_MARK, /* __u32 */
+ XFRMA_SET_MARK_MASK, /* __u32 */
+ XFRMA_IF_ID, /* __u32 */
+ __XFRMA_MAX
+
+#define XFRMA_OUTPUT_MARK XFRMA_SET_MARK /* Compatibility */
+#define XFRMA_MAX (__XFRMA_MAX - 1)
+};
+
+struct xfrm_mark {
+ __u32 v; /* value */
+ __u32 m; /* mask */
+};
+
+enum xfrm_sadattr_type_t {
+ XFRMA_SAD_UNSPEC,
+ XFRMA_SAD_CNT,
+ XFRMA_SAD_HINFO,
+ __XFRMA_SAD_MAX
+
+#define XFRMA_SAD_MAX (__XFRMA_SAD_MAX - 1)
+};
+
+struct xfrmu_sadhinfo {
+ __u32 sadhcnt; /* current hash bkts */
+ __u32 sadhmcnt; /* max allowed hash bkts */
+};
+
+enum xfrm_spdattr_type_t {
+ XFRMA_SPD_UNSPEC,
+ XFRMA_SPD_INFO,
+ XFRMA_SPD_HINFO,
+ XFRMA_SPD_IPV4_HTHRESH,
+ XFRMA_SPD_IPV6_HTHRESH,
+ __XFRMA_SPD_MAX
+
+#define XFRMA_SPD_MAX (__XFRMA_SPD_MAX - 1)
+};
+
+struct xfrmu_spdinfo {
+ __u32 incnt;
+ __u32 outcnt;
+ __u32 fwdcnt;
+ __u32 inscnt;
+ __u32 outscnt;
+ __u32 fwdscnt;
+};
+
+struct xfrmu_spdhinfo {
+ __u32 spdhcnt;
+ __u32 spdhmcnt;
+};
+
+struct xfrmu_spdhthresh {
+ __u8 lbits;
+ __u8 rbits;
+};
+
+struct xfrm_usersa_info {
+ struct xfrm_selector sel;
+ struct xfrm_id id;
+ xfrm_address_t saddr;
+ struct xfrm_lifetime_cfg lft;
+ struct xfrm_lifetime_cur curlft;
+ struct xfrm_stats stats;
+ __u32 seq;
+ __u32 reqid;
+ __u16 family;
+ __u8 mode; /* XFRM_MODE_xxx */
+ __u8 replay_window;
+ __u8 flags;
+#define XFRM_STATE_NOECN 1
+#define XFRM_STATE_DECAP_DSCP 2
+#define XFRM_STATE_NOPMTUDISC 4
+#define XFRM_STATE_WILDRECV 8
+#define XFRM_STATE_ICMP 16
+#define XFRM_STATE_AF_UNSPEC 32
+#define XFRM_STATE_ALIGN4 64
+#define XFRM_STATE_ESN 128
+};
+
+#define XFRM_SA_XFLAG_DONT_ENCAP_DSCP 1
+
+struct xfrm_usersa_id {
+ xfrm_address_t daddr;
+ __be32 spi;
+ __u16 family;
+ __u8 proto;
+};
+
+struct xfrm_aevent_id {
+ struct xfrm_usersa_id sa_id;
+ xfrm_address_t saddr;
+ __u32 flags;
+ __u32 reqid;
+};
+
+struct xfrm_userspi_info {
+ struct xfrm_usersa_info info;
+ __u32 min;
+ __u32 max;
+};
+
+struct xfrm_userpolicy_info {
+ struct xfrm_selector sel;
+ struct xfrm_lifetime_cfg lft;
+ struct xfrm_lifetime_cur curlft;
+ __u32 priority;
+ __u32 index;
+ __u8 dir;
+ __u8 action;
+#define XFRM_POLICY_ALLOW 0
+#define XFRM_POLICY_BLOCK 1
+ __u8 flags;
+#define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */
+ /* Automatically expand selector to include matching ICMP payloads. */
+#define XFRM_POLICY_ICMP 2
+ __u8 share;
+};
+
+struct xfrm_userpolicy_id {
+ struct xfrm_selector sel;
+ __u32 index;
+ __u8 dir;
+};
+
+struct xfrm_user_acquire {
+ struct xfrm_id id;
+ xfrm_address_t saddr;
+ struct xfrm_selector sel;
+ struct xfrm_userpolicy_info policy;
+ __u32 aalgos;
+ __u32 ealgos;
+ __u32 calgos;
+ __u32 seq;
+};
+
+struct xfrm_user_expire {
+ struct xfrm_usersa_info state;
+ __u8 hard;
+};
+
+struct xfrm_user_polexpire {
+ struct xfrm_userpolicy_info pol;
+ __u8 hard;
+};
+
+struct xfrm_usersa_flush {
+ __u8 proto;
+};
+
+struct xfrm_user_report {
+ __u8 proto;
+ struct xfrm_selector sel;
+};
+
+/* Used by MIGRATE to pass addresses IKE should use to perform
+ * SA negotiation with the peer */
+struct xfrm_user_kmaddress {
+ xfrm_address_t local;
+ xfrm_address_t remote;
+ __u32 reserved;
+ __u16 family;
+};
+
+struct xfrm_user_migrate {
+ xfrm_address_t old_daddr;
+ xfrm_address_t old_saddr;
+ xfrm_address_t new_daddr;
+ xfrm_address_t new_saddr;
+ __u8 proto;
+ __u8 mode;
+ __u16 reserved;
+ __u32 reqid;
+ __u16 old_family;
+ __u16 new_family;
+};
+
+struct xfrm_user_mapping {
+ struct xfrm_usersa_id id;
+ __u32 reqid;
+ xfrm_address_t old_saddr;
+ xfrm_address_t new_saddr;
+ __be16 old_sport;
+ __be16 new_sport;
+};
+
+struct xfrm_address_filter {
+ xfrm_address_t saddr;
+ xfrm_address_t daddr;
+ __u16 family;
+ __u8 splen;
+ __u8 dplen;
+};
+
+struct xfrm_user_offload {
+ int ifindex;
+ __u8 flags;
+};
+#define XFRM_OFFLOAD_IPV6 1
+#define XFRM_OFFLOAD_INBOUND 2
+
+/* backwards compatibility for userspace */
+#define XFRMGRP_ACQUIRE 1
+#define XFRMGRP_EXPIRE 2
+#define XFRMGRP_SA 4
+#define XFRMGRP_POLICY 8
+#define XFRMGRP_REPORT 0x20
+
+enum xfrm_nlgroups {
+ XFRMNLGRP_NONE,
+#define XFRMNLGRP_NONE XFRMNLGRP_NONE
+ XFRMNLGRP_ACQUIRE,
+#define XFRMNLGRP_ACQUIRE XFRMNLGRP_ACQUIRE
+ XFRMNLGRP_EXPIRE,
+#define XFRMNLGRP_EXPIRE XFRMNLGRP_EXPIRE
+ XFRMNLGRP_SA,
+#define XFRMNLGRP_SA XFRMNLGRP_SA
+ XFRMNLGRP_POLICY,
+#define XFRMNLGRP_POLICY XFRMNLGRP_POLICY
+ XFRMNLGRP_AEVENTS,
+#define XFRMNLGRP_AEVENTS XFRMNLGRP_AEVENTS
+ XFRMNLGRP_REPORT,
+#define XFRMNLGRP_REPORT XFRMNLGRP_REPORT
+ XFRMNLGRP_MIGRATE,
+#define XFRMNLGRP_MIGRATE XFRMNLGRP_MIGRATE
+ XFRMNLGRP_MAPPING,
+#define XFRMNLGRP_MAPPING XFRMNLGRP_MAPPING
+ __XFRMNLGRP_MAX
+};
+#define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1)
+
+#endif /* _LINUX_XFRM_H */
diff --git a/include/linux-private/linux/netfilter/nfnetlink_acct.h b/include/linux/netfilter/nfnetlink_acct.h
index 4858e5d5..4858e5d5 100644
--- a/include/linux-private/linux/netfilter/nfnetlink_acct.h
+++ b/include/linux/netfilter/nfnetlink_acct.h
diff --git a/include/netlink-private/cache-api.h b/include/netlink-private/cache-api.h
index f3d9f01a..c684e797 100644
--- a/include/netlink-private/cache-api.h
+++ b/include/netlink-private/cache-api.h
@@ -237,7 +237,8 @@ struct nl_cache_ops
* @see nl_cache_include()
*/
int (*co_include_event)(struct nl_cache *cache, struct nl_object *obj,
- change_func_t change_cb, void *data);
+ change_func_t change_cb, change_func_v2_t change_cb_v2,
+ void *data);
void (*reserved_1)(void);
void (*reserved_2)(void);
diff --git a/include/netlink-private/netlink.h b/include/netlink-private/netlink.h
index e366d1e9..5f6e3f79 100644
--- a/include/netlink-private/netlink.h
+++ b/include/netlink-private/netlink.h
@@ -18,7 +18,6 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
-#include <math.h>
#include <time.h>
#include <stdarg.h>
#include <ctype.h>
@@ -49,11 +48,11 @@
#include <linux/pkt_sched.h>
#include <linux/pkt_cls.h>
#include <linux/gen_stats.h>
-#include <linux/ip_mp_alg.h>
#include <linux/atm.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/snmp.h>
+#include <linux/xfrm.h>
#ifndef DISABLE_PTHREADS
#include <pthread.h>
@@ -70,11 +69,11 @@
#define NSEC_PER_SEC 1000000000L
struct trans_tbl {
- int i;
+ uint64_t i;
const char *a;
};
-#define __ADD(id, name) { .i = id, .a = #name },
+#define __ADD(id, name) { .i = id, .a = #name }
struct trans_list {
int i;
@@ -85,11 +84,14 @@ struct trans_list {
#ifdef NL_DEBUG
#define NL_DBG(LVL,FMT,ARG...) \
do { \
- if (LVL <= nl_debug) \
+ if (LVL <= nl_debug) { \
+ int _errsv = errno; \
fprintf(stderr, \
"DBG<" #LVL ">%20s:%-4u %s: " FMT, \
__FILE__, __LINE__, \
- __PRETTY_FUNCTION__, ##ARG); \
+ __func__, ##ARG); \
+ errno = _errsv; \
+ } \
} while (0)
#else /* NL_DEBUG */
#define NL_DBG(LVL,FMT,ARG...) do { } while(0)
@@ -98,7 +100,7 @@ struct trans_list {
#define BUG() \
do { \
fprintf(stderr, "BUG at file position %s:%d:%s\n", \
- __FILE__, __LINE__, __PRETTY_FUNCTION__); \
+ __FILE__, __LINE__, __func__); \
assert(0); \
} while (0)
@@ -112,7 +114,7 @@ struct trans_list {
#define APPBUG(msg) \
do { \
fprintf(stderr, "APPLICATION BUG: %s:%d:%s: %s\n", \
- __FILE__, __LINE__, __PRETTY_FUNCTION__, msg); \
+ __FILE__, __LINE__, __func__, msg); \
assert(0); \
} while(0)
@@ -132,8 +134,9 @@ extern char *__flags2str(int, char *, size_t, const struct trans_tbl *, size_t);
extern int __str2flags(const char *, const struct trans_tbl *, size_t);
extern void dump_from_ops(struct nl_object *, struct nl_dump_params *);
+extern struct rtnl_link *link_lookup(struct nl_cache *cache, int ifindex);
-static inline int nl_cb_call(struct nl_cb *cb, int type, struct nl_msg *msg)
+static inline int nl_cb_call(struct nl_cb *cb, enum nl_cb_type type, struct nl_msg *msg)
{
int ret;
@@ -156,14 +159,14 @@ static inline int nl_cb_call(struct nl_cb *cb, int type, struct nl_msg *msg)
#define __deprecated __attribute__ ((deprecated))
#define min(x,y) ({ \
- typeof(x) _x = (x); \
- typeof(y) _y = (y); \
+ __typeof__(x) _x = (x); \
+ __typeof__(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; })
#define max(x,y) ({ \
- typeof(x) _x = (x); \
- typeof(y) _y = (y); \
+ __typeof__(x) _x = (x); \
+ __typeof__(y) _y = (y); \
(void) (&_x == &_y); \
_x > _y ? _x : _y; })
@@ -183,7 +186,7 @@ static inline void rtnl_copy_ratespec(struct rtnl_ratespec *dst,
dst->rs_overhead = src->overhead;
dst->rs_cell_align = src->cell_align;
dst->rs_mpu = src->mpu;
- dst->rs_rate = src->rate;
+ dst->rs_rate64 = src->rate;
}
static inline void rtnl_rcopy_ratespec(struct tc_ratespec *dst,
@@ -193,10 +196,10 @@ static inline void rtnl_rcopy_ratespec(struct tc_ratespec *dst,
dst->overhead = src->rs_overhead;
dst->cell_align = src->rs_cell_align;
dst->mpu = src->rs_mpu;
- dst->rate = src->rs_rate;
+ dst->rate = src->rs_rate64 > 0xFFFFFFFFull ? 0xFFFFFFFFull : (uint32_t) src->rs_rate64;
}
-static inline char *nl_cache_name(struct nl_cache *cache)
+static inline const char *nl_cache_name(struct nl_cache *cache)
{
return cache->c_ops ? cache->c_ops->co_name : "unknown";
}
@@ -273,4 +276,14 @@ static inline void nl_write_unlock(pthread_rwlock_t *lock)
#define nl_write_unlock(LOCK) do { } while(0)
#endif
+static inline int rtnl_tc_calc_txtime64(int bufsize, uint64_t rate)
+{
+ return ((double) bufsize / (double) rate) * 1000000.0;
+}
+
+static inline int rtnl_tc_calc_bufsize64(int txtime, uint64_t rate)
+{
+ return ((double) txtime * (double) rate) / 1000000.0;
+}
+
#endif
diff --git a/include/netlink-private/object-api.h b/include/netlink-private/object-api.h
index f4fd71e5..517e6720 100644
--- a/include/netlink-private/object-api.h
+++ b/include/netlink-private/object-api.h
@@ -126,6 +126,8 @@ extern "C" {
* #define MY_ATTR_FOO (1<<0)
* #define MY_ATTR_BAR (1<<1)
*
+ * // Bit 31 for attributes is reserved for 32-bit API.
+ *
* // When assigning an optional attribute to the object, make sure
* // to mark its availability.
* my_obj->foo = 123123;
@@ -189,7 +191,7 @@ extern "C" {
struct nl_list_head ce_list; \
int ce_msgtype; \
int ce_flags; \
- uint32_t ce_mask;
+ uint64_t ce_mask;
struct nl_object
{
@@ -258,7 +260,7 @@ struct nl_object
* @endcode
*/
#define ATTR_DIFF(LIST, ATTR, A, B, EXPR) \
-({ int diff = 0; \
+({ uint64_t diff = 0; \
if (((LIST) & (ATTR)) && ATTR_MISMATCH(A, B, ATTR, EXPR)) \
diff = ATTR; \
diff; })
@@ -333,8 +335,8 @@ struct nl_object_ops
* The function must return a bitmask with the relevant bit
* set for each attribute that mismatches.
*/
- int (*oo_compare)(struct nl_object *, struct nl_object *,
- uint32_t, int);
+ uint64_t (*oo_compare)(struct nl_object *, struct nl_object *,
+ uint64_t, int);
/**
diff --git a/include/netlink-private/route/link/api.h b/include/netlink-private/route/link/api.h
index bb98cccb..6d30bf7c 100644
--- a/include/netlink-private/route/link/api.h
+++ b/include/netlink-private/route/link/api.h
@@ -60,6 +60,10 @@ struct rtnl_link_info_ops
* in either io_alloc() or io_parse(). */
void (*io_free)(struct rtnl_link *);
+ /** Called to compare link info parameters between two links. */
+ int (*io_compare)(struct rtnl_link *, struct rtnl_link *,
+ int flags);
+
struct nl_list_head io_list;
};
@@ -115,6 +119,16 @@ struct rtnl_link_af_ops
int (*ao_fill_af)(struct rtnl_link *,
struct nl_msg *msg, void *);
+ /** Called if the full IFLA_AF_SPEC data needs to be parsed. Typically
+ * stores the parsed data in the address family specific buffer. */
+ int (*ao_parse_af_full)(struct rtnl_link *,
+ struct nlattr *, void *);
+
+ /** Called for GETLINK message to the kernel. Used to append
+ * link address family specific attributes to the request message. */
+ int (*ao_get_af)(struct nl_msg *msg,
+ uint32_t *ext_filter_mask);
+
/** Dump address family specific link attributes */
void (*ao_dump[NL_DUMP_MAX+1])(struct rtnl_link *,
struct nl_dump_params *,
@@ -132,6 +146,35 @@ struct rtnl_link_af_ops
*/
int (*ao_compare)(struct rtnl_link *,
struct rtnl_link *, int, uint32_t, int);
+
+ /* RTM_NEWLINK override
+ *
+ * Called if a change link request is set to the kernel. If this returns
+ * anything other than zero, RTM_NEWLINK will be overriden with
+ * RTM_SETLINK when rtnl_link_build_change_request() is called.
+ */
+ int (*ao_override_rtm)(struct rtnl_link *);
+
+ /** Called if a link message is sent to the kernel. Must append the
+ * link protocol specific attributes to the message. (IFLA_PROTINFO) */
+ int (*ao_fill_pi)(struct rtnl_link *,
+ struct nl_msg *msg, void *);
+
+ /** PROTINFO type
+ *
+ * Called if a link message is sent to the kernel. If this is set,
+ * the default IFLA_PROTINFO is bitmasked with what is specified
+ * here. (eg. NLA_F_NESTED)
+ */
+ const int ao_fill_pi_flags;
+
+ /** IFLA_AF_SPEC nesting override
+ *
+ * Called if a link message is sent to the kernel. If this is set,
+ * the AF specific nest is not created. Instead, AF specific attributes
+ * are nested directly in the IFLA_AF_SPEC attribute.
+ */
+ const int ao_fill_af_no_nest;
};
extern struct rtnl_link_af_ops *rtnl_link_af_ops_lookup(unsigned int);
@@ -145,6 +188,9 @@ extern int rtnl_link_af_unregister(struct rtnl_link_af_ops *);
extern int rtnl_link_af_data_compare(struct rtnl_link *a,
struct rtnl_link *b,
int family);
+extern int rtnl_link_info_data_compare(struct rtnl_link *a,
+ struct rtnl_link *b,
+ int flags);
#ifdef __cplusplus
}
diff --git a/include/netlink-private/route/link/sriov.h b/include/netlink-private/route/link/sriov.h
new file mode 100644
index 00000000..ac653ed1
--- /dev/null
+++ b/include/netlink-private/route/link/sriov.h
@@ -0,0 +1,34 @@
+/*
+ * include/netlink-private/route/link/sriov.h SRIOV VF Info
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2016 Intel Corp. All rights reserved.
+ * Copyright (c) 2016 Jef Oliver <jef.oliver@intel.com>
+ */
+
+#ifndef NETLINK_PRIV_LINK_SRIOV_H_
+#define NETLINK_PRIV_LINK_SRIOV_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link/sriov.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_link_sriov_clone(struct rtnl_link *, struct rtnl_link *);
+extern void rtnl_link_sriov_dump_details(struct rtnl_link *, struct nl_dump_params *);
+extern void rtnl_link_sriov_dump_stats(struct rtnl_link *, struct nl_dump_params *);
+extern int rtnl_link_sriov_fill_vflist(struct nl_msg *, struct rtnl_link *);
+extern void rtnl_link_sriov_free_data(struct rtnl_link *);
+extern int rtnl_link_sriov_parse_vflist(struct rtnl_link *, struct nlattr **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink-private/route/mpls.h b/include/netlink-private/route/mpls.h
new file mode 100644
index 00000000..502fd34a
--- /dev/null
+++ b/include/netlink-private/route/mpls.h
@@ -0,0 +1,15 @@
+#ifndef MPLS_H_
+#define MPLS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char *mpls_ntop(int af, const void *addr, char *buf, size_t buflen);
+extern int mpls_pton(int af, const char *src, void *addr, size_t alen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink-private/route/nexthop-encap.h b/include/netlink-private/route/nexthop-encap.h
new file mode 100644
index 00000000..dde1bfbe
--- /dev/null
+++ b/include/netlink-private/route/nexthop-encap.h
@@ -0,0 +1,35 @@
+#ifndef NETLINK_NEXTHOP_ENCAP_H_
+#define NETLINK_NEXTHOP_ENCAP_H_
+
+struct nh_encap_ops {
+ uint16_t encap_type;
+
+ int (*build_msg)(struct nl_msg *msg, void *priv);
+ int (*parse_msg)(struct nlattr *nla, struct rtnl_nexthop *rtnh);
+
+ int (*compare)(void *a, void *b);
+
+ void (*dump)(void *priv, struct nl_dump_params *dp);
+ void (*destructor)(void *priv);
+};
+
+struct rtnl_nh_encap;
+
+/*
+ * generic nexthop encap
+ */
+void nh_set_encap(struct rtnl_nexthop *nh, struct rtnl_nh_encap *rtnh_encap);
+
+int nh_encap_parse_msg(struct nlattr *encap, struct nlattr *encap_type,
+ struct rtnl_nexthop *rtnh);
+int nh_encap_build_msg(struct nl_msg *msg, struct rtnl_nh_encap *rtnh_encap);
+
+void nh_encap_dump(struct rtnl_nh_encap *rtnh_encap, struct nl_dump_params *dp);
+
+int nh_encap_compare(struct rtnl_nh_encap *a, struct rtnl_nh_encap *b);
+
+/*
+ * MPLS encap
+ */
+extern struct nh_encap_ops mpls_encap_ops;
+#endif
diff --git a/include/netlink-private/route/tc-api.h b/include/netlink-private/route/tc-api.h
index bf0c8a3b..7158ce5c 100644
--- a/include/netlink-private/route/tc-api.h
+++ b/include/netlink-private/route/tc-api.h
@@ -110,13 +110,14 @@ extern void rtnl_tc_dump_details(struct nl_object *,
struct nl_dump_params *);
extern void rtnl_tc_dump_stats(struct nl_object *,
struct nl_dump_params *);
-extern int rtnl_tc_compare(struct nl_object *,
+extern uint64_t rtnl_tc_compare(struct nl_object *,
struct nl_object *,
- uint32_t, int);
+ uint64_t, int);
+void * rtnl_tc_data_peek(struct rtnl_tc *tc);
extern void * rtnl_tc_data(struct rtnl_tc *);
extern void * rtnl_tc_data_check(struct rtnl_tc *,
- struct rtnl_tc_ops *);
+ struct rtnl_tc_ops *, int *);
extern struct rtnl_tc_ops * rtnl_tc_lookup_ops(enum rtnl_tc_type,
const char *);
diff --git a/include/netlink-private/socket.h b/include/netlink-private/socket.h
index 86a440c5..9ceecfd1 100644
--- a/include/netlink-private/socket.h
+++ b/include/netlink-private/socket.h
@@ -19,7 +19,7 @@ extern "C" {
#endif
int _nl_socket_is_local_port_unspecified (struct nl_sock *sk);
-uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk);
+uint32_t _nl_socket_set_local_port_no_release(struct nl_sock *sk, int generate_other);
void _nl_socket_used_ports_release_all(const uint32_t *used_ports);
void _nl_socket_used_ports_set(uint32_t *used_ports, uint32_t port);
diff --git a/include/netlink-private/tc.h b/include/netlink-private/tc.h
index d0cb283c..b0f9c506 100644
--- a/include/netlink-private/tc.h
+++ b/include/netlink-private/tc.h
@@ -32,10 +32,11 @@ extern "C" {
#define TCA_ATTR_MPU 0x0800
#define TCA_ATTR_OVERHEAD 0x1000
#define TCA_ATTR_LINKTYPE 0x2000
-#define TCA_ATTR_MAX TCA_ATTR_LINKTYPE
+#define TCA_ATTR_CHAIN 0x4000
+#define TCA_ATTR_MAX TCA_ATTR_CHAIN
extern int tca_parse(struct nlattr **, int, struct rtnl_tc *,
- struct nla_policy *);
+ const struct nla_policy *);
#define RTNL_TC_RTABLE_SIZE 256
diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h
index 3ff4fe1a..97af3e51 100644
--- a/include/netlink-private/types.h
+++ b/include/netlink-private/types.h
@@ -20,14 +20,25 @@
#include <netlink/route/route.h>
#include <netlink/idiag/idiagnl.h>
#include <netlink/netfilter/ct.h>
+#include <netlink-private/object-api.h>
#include <netlink-private/route/tc-api.h>
+#include <netlink-private/route/link/sriov.h>
+#include <netlink-private/route/nexthop-encap.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/genetlink.h>
#include <linux/tc_act/tc_mirred.h>
+#include <linux/tc_act/tc_skbedit.h>
+#include <linux/tc_act/tc_gact.h>
+#include <linux/tc_act/tc_vlan.h>
+#include <linux/sock_diag.h>
+#include <linux/fib_rules.h>
-#define NL_SOCK_BUFSIZE_SET (1<<0)
#define NL_SOCK_PASSCRED (1<<1)
#define NL_OWN_PORT (1<<2)
#define NL_MSG_PEEK (1<<3)
-#define NL_NO_AUTO_ACK (1<<4)
+#define NL_MSG_PEEK_EXPLICIT (1<<4)
+#define NL_NO_AUTO_ACK (1<<5)
#define NL_MSG_CRED_PRESENT 1
@@ -35,6 +46,7 @@ struct nl_cache_ops;
struct nl_sock;
struct nl_object;
struct nl_hash_table;
+struct nl_vf_vlans;
struct nl_cb
{
@@ -95,6 +107,7 @@ struct nl_cache_assoc
{
struct nl_cache * ca_cache;
change_func_t ca_change;
+ change_func_v2_t ca_change_v2;
void * ca_change_data;
};
@@ -111,6 +124,7 @@ struct nl_cache_mngr
struct nl_parser_param;
#define LOOSE_COMPARISON 1
+#define ID_COMPARISON 2
#define NL_OBJ_MARK 1
@@ -152,6 +166,26 @@ struct rtnl_link_map
uint8_t lm_port;
};
+struct rtnl_link_vf
+{
+ struct nl_list_head vf_list;
+ int ce_refcnt;
+ uint32_t ce_mask;
+ uint32_t vf_index;
+ uint64_t vf_guid_node;
+ uint64_t vf_guid_port;
+ uint32_t vf_linkstate;
+ struct nl_addr * vf_lladdr;
+ uint32_t vf_max_tx_rate;
+ uint32_t vf_min_tx_rate;
+ uint32_t vf_rate;
+ uint32_t vf_rss_query_en;
+ uint32_t vf_spoofchk;
+ uint64_t vf_stats[RTNL_LINK_VF_STATS_MAX+1];
+ uint32_t vf_trust;
+ struct nl_vf_vlans * vf_vlans;
+};
+
#define IFQDISCSIZ 32
struct rtnl_link
@@ -164,8 +198,9 @@ struct rtnl_link
uint32_t l_index;
uint32_t l_flags;
uint32_t l_change;
- uint32_t l_mtu;
+ uint32_t l_mtu;
uint32_t l_link;
+ int32_t l_link_netnsid;
uint32_t l_txqlen;
uint32_t l_weight;
uint32_t l_master;
@@ -180,6 +215,7 @@ struct rtnl_link
uint8_t l_linkmode;
/* 2 byte hole */
char * l_info_kind;
+ char * l_info_slave_kind;
struct rtnl_link_info_ops * l_info_ops;
void * l_af_data[AF_MAX];
void * l_info;
@@ -187,13 +223,19 @@ struct rtnl_link
uint32_t l_promiscuity;
uint32_t l_num_tx_queues;
uint32_t l_num_rx_queues;
+ uint32_t l_gso_max_segs;
+ uint32_t l_gso_max_size;
uint32_t l_group;
uint8_t l_carrier;
/* 3 byte hole */
+ uint32_t l_carrier_changes;
struct rtnl_link_af_ops * l_af_ops;
struct nl_data * l_phys_port_id;
+ char l_phys_port_name[IFNAMSIZ];
+ struct nl_data * l_phys_switch_id;
int l_ns_fd;
pid_t l_ns_pid;
+ struct rtnl_link_vf * l_vf_list;
};
struct rtnl_ncacheinfo
@@ -220,6 +262,7 @@ struct rtnl_neigh
uint32_t n_state_mask;
uint32_t n_flag_mask;
uint32_t n_master;
+ uint16_t n_vlan;
};
@@ -261,6 +304,12 @@ struct rtnl_addr
struct rtnl_link *a_link;
};
+struct rtnl_nh_encap
+{
+ struct nh_encap_ops *ops;
+ void *priv; /* private data for encap type */
+};
+
struct rtnl_nexthop
{
uint8_t rtnh_flags;
@@ -272,6 +321,9 @@ struct rtnl_nexthop
uint32_t ce_mask; /* HACK to support attr macros */
struct nl_list_head rtnh_list;
uint32_t rtnh_realms;
+ struct nl_addr * rtnh_newdst;
+ struct nl_addr * rtnh_via;
+ struct rtnl_nh_encap * rtnh_encap;
};
struct rtnl_route
@@ -286,6 +338,7 @@ struct rtnl_route
uint8_t rt_scope;
uint8_t rt_type;
uint8_t rt_nmetrics;
+ uint8_t rt_ttl_propagate;
uint32_t rt_flags;
struct nl_addr * rt_dst;
struct nl_addr * rt_src;
@@ -307,7 +360,9 @@ struct rtnl_rule
uint8_t r_family;
uint8_t r_action;
uint8_t r_dsfield; /* ipv4 only */
- uint8_t r_unused;
+ uint8_t r_l3mdev;
+ uint8_t r_protocol; /* protocol that installed rule */
+ uint8_t r_ip_proto; /* IP/IPv6 protocol */
uint32_t r_table;
uint32_t r_flags;
uint32_t r_prio;
@@ -319,6 +374,9 @@ struct rtnl_rule
struct nl_addr *r_dst;
char r_iifname[IFNAMSIZ];
char r_oifname[IFNAMSIZ];
+
+ struct fib_rule_port_range r_sport;
+ struct fib_rule_port_range r_dport;
};
struct rtnl_neightbl_parms
@@ -437,11 +495,11 @@ struct rtnl_neightbl
struct rtnl_ratespec
{
- uint8_t rs_cell_log;
+ uint64_t rs_rate64;
uint16_t rs_overhead;
int16_t rs_cell_align;
uint16_t rs_mpu;
- uint32_t rs_rate;
+ uint8_t rs_cell_log;
};
struct rtnl_tstats
@@ -485,7 +543,8 @@ struct rtnl_tstats
struct nl_data * pre ##_subdata; \
struct rtnl_link * pre ##_link; \
struct rtnl_tc_ops * pre ##_ops; \
- enum rtnl_tc_type pre ##_type
+ enum rtnl_tc_type pre ##_type; \
+ uint32_t pre ##_chain
struct rtnl_tc
{
@@ -520,6 +579,20 @@ struct rtnl_mirred
struct tc_mirred m_parm;
};
+struct rtnl_skbedit
+{
+ struct tc_skbedit s_parm;
+ uint32_t s_flags;
+ uint32_t s_mark;
+ uint32_t s_prio;
+ uint16_t s_queue_mapping;
+};
+
+struct rtnl_gact
+{
+ struct tc_gact g_parm;
+};
+
struct rtnl_u32
{
uint32_t cu_divisor;
@@ -528,12 +601,21 @@ struct rtnl_u32
uint32_t cu_link;
struct nl_data * cu_pcnt;
struct nl_data * cu_selector;
+ struct nl_data * cu_mark;
struct rtnl_act* cu_act;
struct nl_data * cu_police;
char cu_indev[IFNAMSIZ];
int cu_mask;
};
+struct rtnl_mall
+{
+ uint32_t m_classid;
+ uint32_t m_flags;
+ struct rtnl_act *m_act;
+ int m_mask;
+};
+
struct rtnl_cgroup
{
struct rtnl_ematch_tree *cg_ematch;
@@ -600,6 +682,20 @@ struct rtnl_prio
uint32_t qp_mask;
};
+struct rtnl_mqprio
+{
+ uint8_t qm_num_tc;
+ uint8_t qm_prio_map[TC_QOPT_BITMASK + 1];
+ uint8_t qm_hw;
+ uint16_t qm_count[TC_QOPT_MAX_QUEUE];
+ uint16_t qm_offset[TC_QOPT_MAX_QUEUE];
+ uint16_t qm_mode;
+ uint16_t qm_shaper;
+ uint64_t qm_min_rate[TC_QOPT_MAX_QUEUE];
+ uint64_t qm_max_rate[TC_QOPT_MAX_QUEUE];
+ uint32_t qm_mask;
+};
+
struct rtnl_tbf
{
uint32_t qt_limit;
@@ -721,6 +817,20 @@ struct rtnl_fq_codel
uint32_t fq_mask;
};
+struct rtnl_hfsc_qdisc
+{
+ uint32_t qh_defcls;
+ uint32_t qh_mask;
+};
+
+struct rtnl_hfsc_class
+{
+ struct tc_service_curve ch_rsc;
+ struct tc_service_curve ch_fsc;
+ struct tc_service_curve ch_usc;
+ uint32_t ch_mask;
+};
+
struct flnl_request
{
NLHDR_COMMON
@@ -986,7 +1096,7 @@ struct idiagnl_msg {
struct idiagnl_meminfo * idiag_meminfo;
struct idiagnl_vegasinfo * idiag_vegasinfo;
struct tcp_info idiag_tcpinfo;
- uint32_t idiag_skmeminfo[IDIAG_SK_MEMINFO_VARS];
+ uint32_t idiag_skmeminfo[SK_MEMINFO_VARS];
};
struct idiagnl_req {
@@ -1000,4 +1110,232 @@ struct idiagnl_req {
uint32_t idiag_states;
uint32_t idiag_dbs;
};
+
+// XFRM related definitions
+
+/* Selector, used as selector both on policy rules (SPD) and SAs. */
+struct xfrmnl_sel {
+ uint32_t refcnt;
+ struct nl_addr* daddr;
+ struct nl_addr* saddr;
+ uint16_t dport;
+ uint16_t dport_mask;
+ uint16_t sport;
+ uint16_t sport_mask;
+ uint16_t family;
+ uint8_t prefixlen_d;
+ uint8_t prefixlen_s;
+ uint8_t proto;
+ int32_t ifindex;
+ uint32_t user;
+};
+
+/* Lifetime configuration, used for both policy rules (SPD) and SAs. */
+struct xfrmnl_ltime_cfg {
+ uint32_t refcnt;
+ uint64_t soft_byte_limit;
+ uint64_t hard_byte_limit;
+ uint64_t soft_packet_limit;
+ uint64_t hard_packet_limit;
+ uint64_t soft_add_expires_seconds;
+ uint64_t hard_add_expires_seconds;
+ uint64_t soft_use_expires_seconds;
+ uint64_t hard_use_expires_seconds;
+};
+
+/* Current lifetime, used for both policy rules (SPD) and SAs. */
+struct xfrmnl_lifetime_cur {
+ uint64_t bytes;
+ uint64_t packets;
+ uint64_t add_time;
+ uint64_t use_time;
+};
+
+struct xfrmnl_replay_state {
+ uint32_t oseq;
+ uint32_t seq;
+ uint32_t bitmap;
+};
+
+struct xfrmnl_replay_state_esn {
+ uint32_t bmp_len;
+ uint32_t oseq;
+ uint32_t seq;
+ uint32_t oseq_hi;
+ uint32_t seq_hi;
+ uint32_t replay_window;
+ uint32_t bmp[0];
+};
+
+struct xfrmnl_mark {
+ uint32_t v; /* value */
+ uint32_t m; /* mask */
+};
+
+/* XFRM AE related definitions */
+
+struct xfrmnl_sa_id {
+ struct nl_addr* daddr;
+ uint32_t spi;
+ uint16_t family;
+ uint8_t proto;
+};
+
+struct xfrmnl_ae {
+ NLHDR_COMMON
+
+ struct xfrmnl_sa_id sa_id;
+ struct nl_addr* saddr;
+ uint32_t flags;
+ uint32_t reqid;
+ struct xfrmnl_mark mark;
+ struct xfrmnl_lifetime_cur lifetime_cur;
+ uint32_t replay_maxage;
+ uint32_t replay_maxdiff;
+ struct xfrmnl_replay_state replay_state;
+ struct xfrmnl_replay_state_esn* replay_state_esn;
+};
+
+/* XFRM SA related definitions */
+
+struct xfrmnl_id {
+ struct nl_addr* daddr;
+ uint32_t spi;
+ uint8_t proto;
+};
+
+struct xfrmnl_stats {
+ uint32_t replay_window;
+ uint32_t replay;
+ uint32_t integrity_failed;
+};
+
+struct xfrmnl_algo_aead {
+ char alg_name[64];
+ uint32_t alg_key_len; /* in bits */
+ uint32_t alg_icv_len; /* in bits */
+ char alg_key[0];
+};
+
+struct xfrmnl_algo_auth {
+ char alg_name[64];
+ uint32_t alg_key_len; /* in bits */
+ uint32_t alg_trunc_len; /* in bits */
+ char alg_key[0];
+};
+
+struct xfrmnl_algo {
+ char alg_name[64];
+ uint32_t alg_key_len; /* in bits */
+ char alg_key[0];
+};
+
+struct xfrmnl_encap_tmpl {
+ uint16_t encap_type;
+ uint16_t encap_sport;
+ uint16_t encap_dport;
+ struct nl_addr* encap_oa;
+};
+
+struct xfrmnl_sa {
+ NLHDR_COMMON
+
+ struct xfrmnl_sel* sel;
+ struct xfrmnl_id id;
+ struct nl_addr* saddr;
+ struct xfrmnl_ltime_cfg* lft;
+ struct xfrmnl_lifetime_cur curlft;
+ struct xfrmnl_stats stats;
+ uint32_t seq;
+ uint32_t reqid;
+ uint16_t family;
+ uint8_t mode; /* XFRM_MODE_xxx */
+ uint8_t replay_window;
+ uint8_t flags;
+ struct xfrmnl_algo_aead* aead;
+ struct xfrmnl_algo_auth* auth;
+ struct xfrmnl_algo* crypt;
+ struct xfrmnl_algo* comp;
+ struct xfrmnl_encap_tmpl* encap;
+ uint32_t tfcpad;
+ struct nl_addr* coaddr;
+ struct xfrmnl_mark mark;
+ struct xfrmnl_user_sec_ctx* sec_ctx;
+ uint32_t replay_maxage;
+ uint32_t replay_maxdiff;
+ struct xfrmnl_replay_state replay_state;
+ struct xfrmnl_replay_state_esn* replay_state_esn;
+ uint8_t hard;
+};
+
+struct xfrmnl_usersa_flush {
+ uint8_t proto;
+};
+
+
+/* XFRM SP related definitions */
+
+struct xfrmnl_userpolicy_id {
+ struct xfrmnl_sel sel;
+ uint32_t index;
+ uint8_t dir;
+};
+
+struct xfrmnl_user_sec_ctx {
+ uint16_t len;
+ uint16_t exttype;
+ uint8_t ctx_alg;
+ uint8_t ctx_doi;
+ uint16_t ctx_len;
+ char ctx[0];
+};
+
+struct xfrmnl_userpolicy_type {
+ uint8_t type;
+ uint16_t reserved1;
+ uint16_t reserved2;
+};
+
+struct xfrmnl_user_tmpl {
+ struct xfrmnl_id id;
+ uint16_t family;
+ struct nl_addr* saddr;
+ uint32_t reqid;
+ uint8_t mode;
+ uint8_t share;
+ uint8_t optional;
+ uint32_t aalgos;
+ uint32_t ealgos;
+ uint32_t calgos;
+ struct nl_list_head utmpl_list;
+};
+
+struct xfrmnl_sp {
+ NLHDR_COMMON
+
+ struct xfrmnl_sel* sel;
+ struct xfrmnl_ltime_cfg* lft;
+ struct xfrmnl_lifetime_cur curlft;
+ uint32_t priority;
+ uint32_t index;
+ uint8_t dir;
+ uint8_t action;
+ uint8_t flags;
+ uint8_t share;
+ struct xfrmnl_user_sec_ctx* sec_ctx;
+ struct xfrmnl_userpolicy_type uptype;
+ uint32_t nr_user_tmpl;
+ struct nl_list_head usertmpl_list;
+ struct xfrmnl_mark mark;
+};
+
+struct rtnl_vlan
+{
+ struct tc_vlan v_parm;
+ uint16_t v_vid;
+ uint16_t v_proto;
+ uint8_t v_prio;
+ uint32_t v_flags;
+};
+
#endif
diff --git a/include/netlink-private/utils.h b/include/netlink-private/utils.h
new file mode 100644
index 00000000..f33a2f84
--- /dev/null
+++ b/include/netlink-private/utils.h
@@ -0,0 +1,223 @@
+/*
+ * netlink-private/utils.h Local Utility Functions
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2003-2012 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_UTILS_PRIV_H_
+#define NETLINK_UTILS_PRIV_H_
+
+#include <byteswap.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define ntohll(x) (x)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define ntohll(x) bswap_64((x))
+#endif
+#define htonll(x) ntohll(x)
+
+/*****************************************************************************/
+
+#define _NL_STRINGIFY_ARG(contents) #contents
+#define _NL_STRINGIFY(macro_or_string) _NL_STRINGIFY_ARG (macro_or_string)
+
+/*****************************************************************************/
+
+#if defined (__GNUC__)
+#define _NL_PRAGMA_WARNING_DO(warning) _NL_STRINGIFY(GCC diagnostic ignored warning)
+#elif defined (__clang__)
+#define _NL_PRAGMA_WARNING_DO(warning) _NL_STRINGIFY(clang diagnostic ignored warning)
+#endif
+
+/* you can only suppress a specific warning that the compiler
+ * understands. Otherwise you will get another compiler warning
+ * about invalid pragma option.
+ * It's not that bad however, because gcc and clang often have the
+ * same name for the same warning. */
+
+#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+#define _NL_PRAGMA_WARNING_DISABLE(warning) \
+ _Pragma("GCC diagnostic push") \
+ _Pragma(_NL_PRAGMA_WARNING_DO("-Wpragmas")) \
+ _Pragma(_NL_PRAGMA_WARNING_DO(warning))
+#elif defined (__clang__)
+#define _NL_PRAGMA_WARNING_DISABLE(warning) \
+ _Pragma("clang diagnostic push") \
+ _Pragma(_NL_PRAGMA_WARNING_DO("-Wunknown-warning-option")) \
+ _Pragma(_NL_PRAGMA_WARNING_DO(warning))
+#else
+#define _NL_PRAGMA_WARNING_DISABLE(warning)
+#endif
+
+#if defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+#define _NL_PRAGMA_WARNING_REENABLE \
+ _Pragma("GCC diagnostic pop")
+#elif defined (__clang__)
+#define _NL_PRAGMA_WARNING_REENABLE \
+ _Pragma("clang diagnostic pop")
+#else
+#define _NL_PRAGMA_WARNING_REENABLE
+#endif
+
+/*****************************************************************************/
+
+#define _nl_unused __attribute__ ((__unused__))
+#define _nl_auto(fcn) __attribute__ ((__cleanup__(fcn)))
+
+/*****************************************************************************/
+
+#define _NL_STATIC_ASSERT(cond) ((void) sizeof (char[(cond) ? 1 : -1]))
+
+/*****************************************************************************/
+
+#if defined(NL_MORE_ASSERTS) && NL_MORE_ASSERTS > 0
+#define _nl_assert(cond) assert(cond)
+#else
+#define _nl_assert(cond) do { if (0) { assert(cond); } } while (0)
+#endif
+
+/*****************************************************************************/
+
+#define _NL_AUTO_DEFINE_FCN_VOID0(CastType, name, func) \
+static inline void name (void *v) \
+{ \
+ if (*((CastType *) v)) \
+ func (*((CastType *) v)); \
+}
+
+#define _nl_auto_free _nl_auto(_nl_auto_free_fcn)
+_NL_AUTO_DEFINE_FCN_VOID0 (void *, _nl_auto_free_fcn, free)
+
+/*****************************************************************************/
+
+extern const char *nl_strerror_l(int err);
+
+/*****************************************************************************/
+
+/* internal macro to calculate the size of a struct @type up to (and including) @field.
+ * this will be used for .minlen policy fields, so that we require only a field of up
+ * to the given size. */
+#define _nl_offsetofend(type, field) (offsetof (type, field) + sizeof (((type *) NULL)->field))
+
+/*****************************************************************************/
+
+#define _nl_clear_pointer(pp, destroy) \
+ ({ \
+ __typeof__ (*(pp)) *_pp = (pp); \
+ __typeof__ (*_pp) _p; \
+ int _changed = 0; \
+ \
+ if ( _pp \
+ && (_p = *_pp)) { \
+ _nl_unused const void *const _p_check_is_pointer = _p; \
+ \
+ *_pp = NULL; \
+ \
+ (destroy) (_p); \
+ \
+ _changed = 1; \
+ } \
+ _changed; \
+ })
+
+#define _nl_clear_free(pp) _nl_clear_pointer (pp, free)
+
+#define _nl_steal_pointer(pp) \
+ ({ \
+ __typeof__ (*(pp)) *const _pp = (pp); \
+ __typeof__ (*_pp) _p = NULL; \
+ \
+ if ( _pp \
+ && (_p = *_pp)) { \
+ *_pp = NULL; \
+ } \
+ \
+ _p; \
+ })
+
+/*****************************************************************************/
+
+#define _nl_malloc_maybe_a(alloca_maxlen, bytes, to_free) \
+ ({ \
+ const size_t _bytes = (bytes); \
+ __typeof__ (to_free) _to_free = (to_free); \
+ __typeof__ (*_to_free) _ptr; \
+ \
+ _NL_STATIC_ASSERT ((alloca_maxlen) <= 500); \
+ _nl_assert (_to_free && !*_to_free); \
+ \
+ if (_bytes <= (alloca_maxlen)) { \
+ _ptr = alloca (_bytes); \
+ } else { \
+ _ptr = malloc (_bytes); \
+ *_to_free = _ptr; \
+ }; \
+ \
+ _ptr; \
+ })
+
+/*****************************************************************************/
+
+static inline char *
+_nl_strncpy_trunc(char *dst, const char *src, size_t len)
+{
+ /* we don't use/reimplement strlcpy(), because we want the fill-all-with-NUL
+ * behavior of strncpy(). This is just strncpy() with gracefully handling trunction
+ * (and disabling the "-Wstringop-truncation" warning).
+ *
+ * Note that truncation is silently accepted.
+ */
+
+ _NL_PRAGMA_WARNING_DISABLE ("-Wstringop-truncation");
+ _NL_PRAGMA_WARNING_DISABLE ("-Wstringop-overflow");
+
+ if (len > 0) {
+ _nl_assert(dst);
+ _nl_assert(src);
+
+ strncpy(dst, src, len);
+
+ dst[len - 1] = '\0';
+ }
+
+ _NL_PRAGMA_WARNING_REENABLE;
+ _NL_PRAGMA_WARNING_REENABLE;
+
+ return dst;
+}
+
+static inline char *
+_nl_strncpy(char *dst, const char *src, size_t len)
+{
+ /* we don't use/reimplement strlcpy(), because we want the fill-all-with-NUL
+ * behavior of strncpy(). This is just strncpy() with gracefully handling trunction
+ * (and disabling the "-Wstringop-truncation" warning).
+ *
+ * Note that truncation is still a bug and there is an _nl_assert()
+ * against that.
+ */
+
+ if (len > 0) {
+ _nl_assert(dst);
+ _nl_assert(src);
+
+ strncpy(dst, src, len);
+
+ /* Truncation is a bug and we assert against it. But note that this
+ * assertion is disabled by default because we cannot be sure that
+ * there are not wrong uses of _nl_strncpy() where truncation might
+ * happen (wrongly!!). */
+ _nl_assert (memchr(dst, '\0', len));
+
+ dst[len - 1] = '\0';
+ }
+
+ return dst;
+}
+
+#endif
diff --git a/include/netlink/addr.h b/include/netlink/addr.h
index db3e4c20..00ca7846 100644
--- a/include/netlink/addr.h
+++ b/include/netlink/addr.h
@@ -18,46 +18,51 @@
extern "C" {
#endif
+struct nlattr;
+
struct nl_addr;
/* Creation */
extern struct nl_addr * nl_addr_alloc(size_t);
-extern struct nl_addr * nl_addr_alloc_attr(struct nlattr *, int);
-extern struct nl_addr * nl_addr_build(int, void *, size_t);
+extern struct nl_addr * nl_addr_alloc_attr(const struct nlattr *, int);
+extern struct nl_addr * nl_addr_build(int, const void *, size_t);
extern int nl_addr_parse(const char *, int, struct nl_addr **);
-extern struct nl_addr * nl_addr_clone(struct nl_addr *);
+extern struct nl_addr * nl_addr_clone(const struct nl_addr *);
/* Usage Management */
extern struct nl_addr * nl_addr_get(struct nl_addr *);
extern void nl_addr_put(struct nl_addr *);
-extern int nl_addr_shared(struct nl_addr *);
+extern int nl_addr_shared(const struct nl_addr *);
-extern int nl_addr_cmp(struct nl_addr *, struct nl_addr *);
-extern int nl_addr_cmp_prefix(struct nl_addr *, struct nl_addr *);
-extern int nl_addr_iszero(struct nl_addr *);
-extern int nl_addr_valid(char *, int);
-extern int nl_addr_guess_family(struct nl_addr *);
-extern int nl_addr_fill_sockaddr(struct nl_addr *,
+extern int nl_addr_cmp(const struct nl_addr *,
+ const struct nl_addr *);
+extern int nl_addr_cmp_prefix(const struct nl_addr *,
+ const struct nl_addr *);
+extern int nl_addr_iszero(const struct nl_addr *);
+extern int nl_addr_valid(const char *, int);
+extern int nl_addr_guess_family(const struct nl_addr *);
+extern int nl_addr_fill_sockaddr(const struct nl_addr *,
struct sockaddr *, socklen_t *);
-extern int nl_addr_info(struct nl_addr *, struct addrinfo **);
-extern int nl_addr_resolve(struct nl_addr *, char *, size_t);
+extern int nl_addr_info(const struct nl_addr *,
+ struct addrinfo **);
+extern int nl_addr_resolve(const struct nl_addr *, char *, size_t);
/* Access Functions */
extern void nl_addr_set_family(struct nl_addr *, int);
-extern int nl_addr_get_family(struct nl_addr *);
-extern int nl_addr_set_binary_addr(struct nl_addr *, void *,
+extern int nl_addr_get_family(const struct nl_addr *);
+extern int nl_addr_set_binary_addr(struct nl_addr *, const void *,
size_t);
-extern void * nl_addr_get_binary_addr(struct nl_addr *);
-extern unsigned int nl_addr_get_len(struct nl_addr *);
+extern void * nl_addr_get_binary_addr(const struct nl_addr *);
+extern unsigned int nl_addr_get_len(const struct nl_addr *);
extern void nl_addr_set_prefixlen(struct nl_addr *, int);
-extern unsigned int nl_addr_get_prefixlen(struct nl_addr *);
+extern unsigned int nl_addr_get_prefixlen(const struct nl_addr *);
/* Address Family Translations */
extern char * nl_af2str(int, char *, size_t);
extern int nl_str2af(const char *);
/* Translations to Strings */
-extern char * nl_addr2str(struct nl_addr *, char *, size_t);
+extern char * nl_addr2str(const struct nl_addr *, char *, size_t);
#ifdef __cplusplus
}
diff --git a/include/netlink/attr.h b/include/netlink/attr.h
index 82e4c383..e47aa5d5 100644
--- a/include/netlink/attr.h
+++ b/include/netlink/attr.h
@@ -21,6 +21,8 @@
extern "C" {
#endif
+struct nlattr;
+
struct nl_msg;
/**
@@ -44,6 +46,13 @@ enum {
NLA_FLAG, /**< Flag */
NLA_MSECS, /**< Micro seconds (64bit) */
NLA_NESTED, /**< Nested attributes */
+ NLA_NESTED_COMPAT,
+ NLA_NUL_STRING,
+ NLA_BINARY,
+ NLA_S8,
+ NLA_S16,
+ NLA_S32,
+ NLA_S64,
__NLA_TYPE_MAX,
};
@@ -80,13 +89,13 @@ extern int nla_len(const struct nlattr *);
extern int nla_ok(const struct nlattr *, int);
extern struct nlattr * nla_next(const struct nlattr *, int *);
extern int nla_parse(struct nlattr **, int, struct nlattr *,
- int, struct nla_policy *);
-extern int nla_validate(struct nlattr *, int, int,
- struct nla_policy *);
-extern struct nlattr * nla_find(struct nlattr *, int, int);
+ int, const struct nla_policy *);
+extern int nla_validate(const struct nlattr *, int, int,
+ const struct nla_policy *);
+extern struct nlattr * nla_find(const struct nlattr *, int, int);
/* Helper Functions */
-extern int nla_memcpy(void *, struct nlattr *, int);
+extern int nla_memcpy(void *, const struct nlattr *, int);
extern size_t nla_strlcpy(char *, const struct nlattr *, size_t);
extern int nla_memcmp(const struct nlattr *, const void *, size_t);
extern int nla_strcmp(const struct nlattr *, const char *);
@@ -94,40 +103,51 @@ extern int nla_strcmp(const struct nlattr *, const char *);
/* Unspecific attribute */
extern struct nlattr * nla_reserve(struct nl_msg *, int, int);
extern int nla_put(struct nl_msg *, int, int, const void *);
-extern int nla_put_data(struct nl_msg *, int, struct nl_data *);
+extern int nla_put_data(struct nl_msg *, int,
+ const struct nl_data *);
extern int nla_put_addr(struct nl_msg *, int, struct nl_addr *);
/* Integer attribute */
-extern uint8_t nla_get_u8(struct nlattr *);
+extern int8_t nla_get_s8(const struct nlattr *);
+extern int nla_put_s8(struct nl_msg *, int, int8_t);
+extern uint8_t nla_get_u8(const struct nlattr *);
extern int nla_put_u8(struct nl_msg *, int, uint8_t);
-extern uint16_t nla_get_u16(struct nlattr *);
+extern int16_t nla_get_s16(const struct nlattr *);
+extern int nla_put_s16(struct nl_msg *, int, int16_t);
+extern uint16_t nla_get_u16(const struct nlattr *);
extern int nla_put_u16(struct nl_msg *, int, uint16_t);
-extern uint32_t nla_get_u32(struct nlattr *);
+extern int32_t nla_get_s32(const struct nlattr *);
+extern int nla_put_s32(struct nl_msg *, int, int32_t);
+extern uint32_t nla_get_u32(const struct nlattr *);
extern int nla_put_u32(struct nl_msg *, int, uint32_t);
-extern uint64_t nla_get_u64(struct nlattr *);
+extern int64_t nla_get_s64(const struct nlattr *);
+extern int nla_put_s64(struct nl_msg *, int, int64_t);
+extern uint64_t nla_get_u64(const struct nlattr *);
extern int nla_put_u64(struct nl_msg *, int, uint64_t);
/* String attribute */
-extern char * nla_get_string(struct nlattr *);
-extern char * nla_strdup(struct nlattr *);
+extern char * nla_get_string(const struct nlattr *);
+extern char * nla_strdup(const struct nlattr *);
extern int nla_put_string(struct nl_msg *, int, const char *);
/* Flag attribute */
-extern int nla_get_flag(struct nlattr *);
+extern int nla_get_flag(const struct nlattr *);
extern int nla_put_flag(struct nl_msg *, int);
/* Msec attribute */
-extern unsigned long nla_get_msecs(struct nlattr *);
+extern unsigned long nla_get_msecs(const struct nlattr *);
extern int nla_put_msecs(struct nl_msg *, int, unsigned long);
/* Attribute nesting */
-extern int nla_put_nested(struct nl_msg *, int, struct nl_msg *);
+extern int nla_put_nested(struct nl_msg *, int,
+ const struct nl_msg *);
extern struct nlattr * nla_nest_start(struct nl_msg *, int);
extern int nla_nest_end(struct nl_msg *, struct nlattr *);
-extern void nla_nest_cancel(struct nl_msg *, struct nlattr *);
+extern int nla_nest_end_keep_empty(struct nl_msg *, struct nlattr *);
+extern void nla_nest_cancel(struct nl_msg *, const struct nlattr *);
extern int nla_parse_nested(struct nlattr **, int, struct nlattr *,
- struct nla_policy *);
-extern int nla_is_nested(struct nlattr *);
+ const struct nla_policy *);
+extern int nla_is_nested(const struct nlattr *);
/**
* @name Attribute Construction (Exception Based)
@@ -163,6 +183,15 @@ extern int nla_is_nested(struct nlattr *);
} while(0)
/**
+ * Add 8 bit signed integer attribute to netlink message.
+ * @arg msg Netlink message.
+ * @arg attrtype Attribute type.
+ * @arg value Numeric value.
+ */
+#define NLA_PUT_S8(msg, attrtype, value) \
+ NLA_PUT_TYPE(msg, int8_t, attrtype, value)
+
+/**
* Add 8 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
@@ -172,6 +201,15 @@ extern int nla_is_nested(struct nlattr *);
NLA_PUT_TYPE(msg, uint8_t, attrtype, value)
/**
+ * Add 16 bit signed integer attribute to netlink message.
+ * @arg msg Netlink message.
+ * @arg attrtype Attribute type.
+ * @arg value Numeric value.
+ */
+#define NLA_PUT_S16(msg, attrtype, value) \
+ NLA_PUT_TYPE(msg, int16_t, attrtype, value)
+
+/**
* Add 16 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
@@ -181,6 +219,15 @@ extern int nla_is_nested(struct nlattr *);
NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
/**
+ * Add 32 bit signed integer attribute to netlink message.
+ * @arg msg Netlink message.
+ * @arg attrtype Attribute type.
+ * @arg value Numeric value.
+ */
+#define NLA_PUT_S32(msg, attrtype, value) \
+ NLA_PUT_TYPE(msg, int32_t, attrtype, value)
+
+/**
* Add 32 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
@@ -190,6 +237,15 @@ extern int nla_is_nested(struct nlattr *);
NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
/**
+ * Add 64 bit signed integer attribute to netlink message.
+ * @arg msg Netlink message.
+ * @arg attrtype Attribute type.
+ * @arg value Numeric value.
+ */
+#define NLA_PUT_S64(msg, attrtype, value) \
+ NLA_PUT_TYPE(msg, int64_t, attrtype, value)
+
+/**
* Add 64 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
@@ -272,7 +328,7 @@ extern int nla_is_nested(struct nlattr *);
* @arg rem initialized to len, holds bytes currently remaining in stream
*/
#define nla_for_each_nested(pos, nla, rem) \
- for (pos = nla_data(nla), rem = nla_len(nla); \
+ for (pos = (struct nlattr *) nla_data(nla), rem = nla_len(nla); \
nla_ok(pos, rem); \
pos = nla_next(pos, &(rem)))
diff --git a/include/netlink/cache.h b/include/netlink/cache.h
index e21aa1c6..c0797d01 100644
--- a/include/netlink/cache.h
+++ b/include/netlink/cache.h
@@ -35,6 +35,8 @@ enum {
struct nl_cache;
typedef void (*change_func_t)(struct nl_cache *, struct nl_object *, int, void *);
+typedef void (*change_func_v2_t)(struct nl_cache *, struct nl_object *old_obj,
+ struct nl_object *new_obj, uint64_t, int, void *);
/**
* @ingroup cache
@@ -78,6 +80,8 @@ extern int nl_cache_refill(struct nl_sock *,
struct nl_cache *);
extern int nl_cache_pickup(struct nl_sock *,
struct nl_cache *);
+extern int nl_cache_pickup_checkdup(struct nl_sock *,
+ struct nl_cache *);
extern int nl_cache_resync(struct nl_sock *,
struct nl_cache *,
change_func_t,
@@ -86,6 +90,10 @@ extern int nl_cache_include(struct nl_cache *,
struct nl_object *,
change_func_t,
void *);
+extern int nl_cache_include_v2(struct nl_cache *,
+ struct nl_object *,
+ change_func_v2_t,
+ void *);
extern void nl_cache_set_arg1(struct nl_cache *, int);
extern void nl_cache_set_arg2(struct nl_cache *, int);
extern void nl_cache_set_flags(struct nl_cache *, unsigned int);
@@ -152,6 +160,9 @@ extern int nl_cache_mngr_add(struct nl_cache_mngr *,
extern int nl_cache_mngr_add_cache(struct nl_cache_mngr *mngr,
struct nl_cache *cache,
change_func_t cb, void *data);
+extern int nl_cache_mngr_add_cache_v2(struct nl_cache_mngr *mngr,
+ struct nl_cache *cache,
+ change_func_v2_t cb, void *data);
extern int nl_cache_mngr_get_fd(struct nl_cache_mngr *);
extern int nl_cache_mngr_poll(struct nl_cache_mngr *,
int);
@@ -162,6 +173,8 @@ extern void nl_cache_mngr_free(struct nl_cache_mngr *);
extern void nl_cache_ops_get(struct nl_cache_ops *);
extern void nl_cache_ops_put(struct nl_cache_ops *);
+extern void nl_cache_ops_set_flags(struct nl_cache_ops *,
+ unsigned int);
#ifdef __cplusplus
}
diff --git a/include/netlink/cli/link.h b/include/netlink/cli/link.h
index 3f37948d..f2c720ba 100644
--- a/include/netlink/cli/link.h
+++ b/include/netlink/cli/link.h
@@ -17,7 +17,11 @@
extern struct rtnl_link *nl_cli_link_alloc(void);
extern struct nl_cache *nl_cli_link_alloc_cache_family(struct nl_sock *, int);
+extern struct nl_cache *nl_cli_link_alloc_cache_family_flags(struct nl_sock *, int,
+ unsigned int);
extern struct nl_cache *nl_cli_link_alloc_cache(struct nl_sock *);
+extern struct nl_cache *nl_cli_link_alloc_cache_flags(struct nl_sock *,
+ unsigned int);
extern void nl_cli_link_parse_family(struct rtnl_link *, char *);
extern void nl_cli_link_parse_name(struct rtnl_link *, char *);
diff --git a/include/netlink/cli/neigh.h b/include/netlink/cli/neigh.h
index 54400128..1c1be91b 100644
--- a/include/netlink/cli/neigh.h
+++ b/include/netlink/cli/neigh.h
@@ -15,7 +15,8 @@
#include <netlink/route/neighbour.h>
#define nl_cli_neigh_alloc_cache(sk) \
- nl_cli_alloc_cache((sk), "neighbour", rtnl_neigh_alloc_cache)
+ nl_cli_alloc_cache_flags((sk), "neighbour", NL_CACHE_AF_ITER, \
+ rtnl_neigh_alloc_cache_flags)
extern struct rtnl_neigh *nl_cli_neigh_alloc(void);
extern void nl_cli_neigh_parse_dst(struct rtnl_neigh *, char *);
diff --git a/include/netlink/cli/utils.h b/include/netlink/cli/utils.h
index da41c10e..7d69543a 100644
--- a/include/netlink/cli/utils.h
+++ b/include/netlink/cli/utils.h
@@ -22,9 +22,9 @@
#include <stdint.h>
#include <ctype.h>
#include <getopt.h>
-#include <dlfcn.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <sys/select.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
@@ -61,8 +61,10 @@ extern "C" {
#endif
extern uint32_t nl_cli_parse_u32(const char *);
-extern void nl_cli_print_version(void);
-extern void nl_cli_fatal(int, const char *, ...);
+extern void nl_cli_print_version(void)
+ __attribute__((noreturn));
+extern void nl_cli_fatal(int, const char *, ...)
+ __attribute__((noreturn));
extern struct nl_addr * nl_cli_addr_parse(const char *, int);
extern int nl_cli_connect(struct nl_sock *, int);
extern struct nl_sock * nl_cli_alloc_socket(void);
@@ -73,6 +75,10 @@ extern int nl_cli_confirm(struct nl_object *,
extern struct nl_cache *nl_cli_alloc_cache(struct nl_sock *, const char *,
int (*ac)(struct nl_sock *, struct nl_cache **));
+extern struct nl_cache *nl_cli_alloc_cache_flags(struct nl_sock *, const char *,
+ unsigned int flags,
+ int (*ac)(struct nl_sock *, struct nl_cache **, unsigned int));
+
extern void nl_cli_load_module(const char *, const char *);
#ifdef __cplusplus
diff --git a/include/netlink/data.h b/include/netlink/data.h
index 071159ee..45010fe6 100644
--- a/include/netlink/data.h
+++ b/include/netlink/data.h
@@ -18,21 +18,24 @@
extern "C" {
#endif
+struct nlattr;
+
struct nl_data;
/* General */
-extern struct nl_data * nl_data_alloc(void *, size_t);
-extern struct nl_data * nl_data_alloc_attr(struct nlattr *);
-extern struct nl_data * nl_data_clone(struct nl_data *);
-extern int nl_data_append(struct nl_data *, void *, size_t);
+extern struct nl_data * nl_data_alloc(const void *, size_t);
+extern struct nl_data * nl_data_alloc_attr(const struct nlattr *);
+extern struct nl_data * nl_data_clone(const struct nl_data *);
+extern int nl_data_append(struct nl_data *, const void *, size_t);
extern void nl_data_free(struct nl_data *);
/* Access Functions */
-extern void * nl_data_get(struct nl_data *);
-extern size_t nl_data_get_size(struct nl_data *);
+extern void * nl_data_get(const struct nl_data *);
+extern size_t nl_data_get_size(const struct nl_data *);
/* Misc */
-extern int nl_data_cmp(struct nl_data *, struct nl_data *);
+extern int nl_data_cmp(const struct nl_data *,
+ const struct nl_data *);
#ifdef __cplusplus
}
diff --git a/include/netlink/errno.h b/include/netlink/errno.h
index f8b5130c..35710cf6 100644
--- a/include/netlink/errno.h
+++ b/include/netlink/errno.h
@@ -50,8 +50,9 @@ extern "C" {
#define NLE_NODEV 31
#define NLE_IMMUTABLE 32
#define NLE_DUMP_INTR 33
+#define NLE_ATTRSIZE 34
-#define NLE_MAX NLE_DUMP_INTR
+#define NLE_MAX NLE_ATTRSIZE
extern const char * nl_geterror(int);
extern void nl_perror(int, const char *);
diff --git a/include/netlink/fib_lookup/lookup.h b/include/netlink/fib_lookup/lookup.h
index 8bf27b8d..b3c7b5f4 100644
--- a/include/netlink/fib_lookup/lookup.h
+++ b/include/netlink/fib_lookup/lookup.h
@@ -35,6 +35,13 @@ extern int flnl_lookup(struct nl_sock *,
struct flnl_request *,
struct nl_cache *);
+extern int flnl_result_get_table_id(struct flnl_result *res);
+extern int flnl_result_get_prefixlen(struct flnl_result *res);
+extern int flnl_result_get_nexthop_sel(struct flnl_result *res);
+extern int flnl_result_get_type(struct flnl_result *res);
+extern int flnl_result_get_scope(struct flnl_result *res);
+extern int flnl_result_get_error(struct flnl_result *res);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/netlink/genl/genl.h b/include/netlink/genl/genl.h
index e455581b..c4ac137d 100644
--- a/include/netlink/genl/genl.h
+++ b/include/netlink/genl/genl.h
@@ -29,9 +29,9 @@ extern void * genlmsg_put(struct nl_msg *, uint32_t, uint32_t,
extern int genlmsg_valid_hdr(struct nlmsghdr *, int);
extern int genlmsg_validate(struct nlmsghdr *, int, int,
- struct nla_policy *);
+ const struct nla_policy *);
extern int genlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
- int, struct nla_policy *);
+ int, const struct nla_policy *);
extern struct genlmsghdr *
genlmsg_hdr(struct nlmsghdr *);
extern void * genlmsg_data(const struct genlmsghdr *);
diff --git a/include/netlink/handlers.h b/include/netlink/handlers.h
index e94cd348..4fac1481 100644
--- a/include/netlink/handlers.h
+++ b/include/netlink/handlers.h
@@ -22,10 +22,13 @@
extern "C" {
#endif
+struct nlmsgerr;
+struct sockaddr_nl;
+struct ucred;
+
struct nl_cb;
struct nl_sock;
struct nl_msg;
-struct ucred;
/**
* @name Callback Typedefs
diff --git a/include/netlink/hashtable.h b/include/netlink/hashtable.h
index d9e6ee45..3b40d86c 100644
--- a/include/netlink/hashtable.h
+++ b/include/netlink/hashtable.h
@@ -12,6 +12,9 @@
#ifndef NETLINK_HASHTABLE_H_
#define NETLINK_HASHTABLE_H_
+#include <stddef.h>
+#include <stdint.h>
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/include/netlink/idiag/idiagnl.h b/include/netlink/idiag/idiagnl.h
index d7434cd7..b69cbf17 100644
--- a/include/netlink/idiag/idiagnl.h
+++ b/include/netlink/idiag/idiagnl.h
@@ -13,13 +13,22 @@
#define NETLINK_IDIAGNL_H_
#include <netlink/netlink.h>
+#include <linux/sock_diag.h>
#ifdef __cplusplus
extern "C" {
#endif
+/*************************************************************
+ * The following part contains DEPRECATED names and defines.
+ * Don't use them.
+ *************************************************************/
+
/**
* Inet Diag message types
+ *
+ * deprecated: use TCPDIAG_GETSOCK, DCCPDIAG_GETSOCK and
+ * INET_DIAG_GETSOCK_MAX from linux/inet_diag.h
*/
#define IDIAG_TCPDIAG_GETSOCK 18
#define IDIAG_DCCPDIAG_GETSOCK 19
@@ -28,80 +37,96 @@ extern "C" {
/**
* Socket state identifiers
* @ingroup idiag
+ * @deprecated: use instead the TCP_* defines from netinet/tcp.h.
*/
enum {
- IDIAG_SS_UNKNOWN,
- IDIAG_SS_ESTABLISHED,
- IDIAG_SS_SYN_SENT,
- IDIAG_SS_SYN_RECV,
- IDIAG_SS_FIN_WAIT1,
- IDIAG_SS_FIN_WAIT2,
- IDIAG_SS_TIME_WAIT,
- IDIAG_SS_CLOSE,
- IDIAG_SS_CLOSE_WAIT,
- IDIAG_SS_LAST_ACK,
- IDIAG_SS_LISTEN,
- IDIAG_SS_CLOSING,
- IDIAG_SS_MAX
+ IDIAG_SS_UNKNOWN = 0,
+
+ IDIAG_SS_ESTABLISHED = 1, /* TCP_ESTABLISHED */
+ IDIAG_SS_SYN_SENT = 2, /* TCP_SYN_SENT */
+ IDIAG_SS_SYN_RECV = 3, /* TCP_SYN_RECV */
+ IDIAG_SS_FIN_WAIT1 = 4, /* TCP_FIN_WAIT1 */
+ IDIAG_SS_FIN_WAIT2 = 5, /* TCP_FIN_WAIT2 */
+ IDIAG_SS_TIME_WAIT = 6, /* TCP_TIME_WAIT */
+ IDIAG_SS_CLOSE = 7, /* TCP_CLOSE */
+ IDIAG_SS_CLOSE_WAIT = 8, /* TCP_CLOSE_WAIT */
+ IDIAG_SS_LAST_ACK = 9, /* TCP_LAST_ACK */
+ IDIAG_SS_LISTEN = 10, /* TCP_LISTEN */
+ IDIAG_SS_CLOSING = 11, /* TCP_CLOSING */
+
+ IDIAG_SS_MAX = 12,
};
/**
* Macro to represent all socket states.
* @ingroup idiag
+ * @deprecated
*/
-#define IDIAG_SS_ALL ((1<<IDIAG_SS_MAX)-1)
+#define IDIAG_SS_ALL IDIAGNL_SS_ALL
+
/**
* Inet Diag extended attributes
* @ingroup idiag
- */
+ * @deprecated These attributes should not be used. They mirror the
+ * INET_DIAG_* extension flags from kernel headers. Use those instead. */
enum {
- IDIAG_ATTR_NONE,
- IDIAG_ATTR_MEMINFO,
- IDIAG_ATTR_INFO,
- IDIAG_ATTR_VEGASINFO,
- IDIAG_ATTR_CONG,
- IDIAG_ATTR_TOS,
- IDIAG_ATTR_TCLASS,
- IDIAG_ATTR_SKMEMINFO,
- IDIAG_ATTR_SHUTDOWN,
- IDIAG_ATTR_MAX,
+ IDIAG_ATTR_NONE = 0, /* INET_DIAG_NONE */
+ IDIAG_ATTR_MEMINFO = 1, /* INET_DIAG_MEMINFO */
+ IDIAG_ATTR_INFO = 2, /* INET_DIAG_INFO */
+ IDIAG_ATTR_VEGASINFO = 3, /* INET_DIAG_VEGASINFO */
+ IDIAG_ATTR_CONG = 4, /* INET_DIAG_CONG */
+ IDIAG_ATTR_TOS = 5, /* INET_DIAG_TOS */
+ IDIAG_ATTR_TCLASS = 6, /* INET_DIAG_TCLASS */
+ IDIAG_ATTR_SKMEMINFO = 7, /* INET_DIAG_SKMEMINFO */
+ IDIAG_ATTR_SHUTDOWN = 8, /* INET_DIAG_SHUTDOWN */
+
+ /* IDIAG_ATTR_MAX was wrong, because it did not correspond to
+ * INET_DIAG_MAX. Anyway, freeze it to the previous value. */
+ IDIAG_ATTR_MAX = 9,
+
+ IDIAG_ATTR_ALL = (1<<IDIAG_ATTR_MAX) - 1,
};
-/**
- * Macro to represent all socket attributes.
- * @ingroup idiag
- */
-#define IDIAG_ATTR_ALL ((1<<IDIAG_ATTR_MAX)-1)
+
+/* deprectated keep these only for compatibility, DO NOT USE THEM */
+#define IDIAG_SK_MEMINFO_RMEM_ALLOC 0 /* SK_MEMINFO_RMEM_ALLOC */
+#define IDIAG_SK_MEMINFO_RCVBUF 1 /* SK_MEMINFO_RCVBUF */
+#define IDIAG_SK_MEMINFO_WMEM_ALLOC 2 /* SK_MEMINFO_WMEM_ALLOC */
+#define IDIAG_SK_MEMINFO_SNDBUF 3 /* SK_MEMINFO_SNDBUF */
+#define IDIAG_SK_MEMINFO_FWD_ALLOC 4 /* SK_MEMINFO_FWD_ALLOC */
+#define IDIAG_SK_MEMINFO_WMEM_QUEUED 5 /* SK_MEMINFO_WMEM_QUEUED */
+#define IDIAG_SK_MEMINFO_OPTMEM 6 /* SK_MEMINFO_OPTMEM */
+#define IDIAG_SK_MEMINFO_BACKLOG 7 /* SK_MEMINFO_BACKLOG */
+#define IDIAG_SK_MEMINFO_VARS SK_MEMINFO_VARS
+
+/* deprecated names. */
+#define IDIAG_TIMER_OFF IDIAGNL_TIMER_OFF
+#define IDIAG_TIMER_ON IDIAGNL_TIMER_ON
+#define IDIAG_TIMER_KEEPALIVE IDIAGNL_TIMER_KEEPALIVE
+#define IDIAG_TIMER_TIMEWAIT IDIAGNL_TIMER_TIMEWAIT
+#define IDIAG_TIMER_PERSIST IDIAGNL_TIMER_PERSIST
+#define IDIAG_TIMER_UNKNOWN IDIAGNL_TIMER_UNKNOWN
+
+/*************************************************************/
/**
- * Socket memory info identifiers
+ * Macro to represent all socket states.
* @ingroup idiag
*/
-enum {
- IDIAG_SK_MEMINFO_RMEM_ALLOC,
- IDIAG_SK_MEMINFO_RCVBUF,
- IDIAG_SK_MEMINFO_WMEM_ALLOC,
- IDIAG_SK_MEMINFO_SNDBUF,
- IDIAG_SK_MEMINFO_FWD_ALLOC,
- IDIAG_SK_MEMINFO_WMEM_QUEUED,
- IDIAG_SK_MEMINFO_OPTMEM,
- IDIAG_SK_MEMINFO_BACKLOG,
-
- IDIAG_SK_MEMINFO_VARS,
-};
+#define IDIAGNL_SS_ALL (((1<<12)-1))
/**
* Socket timer indentifiers
* @ingroupd idiag
*/
enum {
- IDIAG_TIMER_OFF,
- IDIAG_TIMER_ON,
- IDIAG_TIMER_KEEPALIVE,
- IDIAG_TIMER_TIMEWAIT,
- IDIAG_TIMER_PERSIST,
- IDIAG_TIMER_UNKNOWN,
+ IDIAGNL_TIMER_OFF = 0,
+ IDIAGNL_TIMER_ON = 1,
+ IDIAGNL_TIMER_KEEPALIVE = 2,
+ IDIAGNL_TIMER_TIMEWAIT = 3,
+ IDIAGNL_TIMER_PERSIST = 4,
+ IDIAGNL_TIMER_UNKNOWN = 5,
};
extern char * idiagnl_state2str(int, char *, size_t);
diff --git a/include/netlink/idiag/msg.h b/include/netlink/idiag/msg.h
index 4aae606f..01e30db0 100644
--- a/include/netlink/idiag/msg.h
+++ b/include/netlink/idiag/msg.h
@@ -19,6 +19,8 @@ extern "C" {
#endif /* __cplusplus */
struct idiagnl_msg;
+
+/* @deprecated: DO NOT USE this variable. */
extern struct nl_object_ops idiagnl_msg_obj_ops;
extern struct idiagnl_msg * idiagnl_msg_alloc(void);
diff --git a/include/netlink/idiag/req.h b/include/netlink/idiag/req.h
index 3c9f8ace..b63a4ce0 100644
--- a/include/netlink/idiag/req.h
+++ b/include/netlink/idiag/req.h
@@ -43,6 +43,10 @@ extern int idiagnl_req_set_src(struct idiagnl_req *,
extern struct nl_addr * idiagnl_req_get_dst(const struct idiagnl_req *);
extern int idiagnl_req_set_dst(struct idiagnl_req *,
struct nl_addr *);
+
+extern int idiagnl_req_parse(struct nlmsghdr *nlh,
+ struct idiagnl_req **result);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/include/netlink/list.h b/include/netlink/list.h
index 28712eda..2f206347 100644
--- a/include/netlink/list.h
+++ b/include/netlink/list.h
@@ -12,6 +12,8 @@
#ifndef NETLINK_LIST_H_
#define NETLINK_LIST_H_
+#include <stddef.h>
+
struct nl_list_head
{
struct nl_list_head * next;
@@ -58,8 +60,8 @@ static inline int nl_list_empty(struct nl_list_head *head)
}
#define nl_container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - ((size_t) &((type *)0)->member));})
+ const __typeof__( ((type *)0)->member ) *__mptr = (ptr);\
+ (type *)( (char *)__mptr - (offsetof(type, member)));})
#define nl_list_entry(ptr, type, member) \
nl_container_of(ptr, type, member)
@@ -77,15 +79,15 @@ static inline int nl_list_empty(struct nl_list_head *head)
nl_list_entry((head)->next, type, member)
#define nl_list_for_each_entry(pos, head, member) \
- for (pos = nl_list_entry((head)->next, typeof(*pos), member); \
+ for (pos = nl_list_entry((head)->next, __typeof__(*pos), member); \
&(pos)->member != (head); \
- (pos) = nl_list_entry((pos)->member.next, typeof(*(pos)), member))
+ (pos) = nl_list_entry((pos)->member.next, __typeof__(*(pos)), member))
#define nl_list_for_each_entry_safe(pos, n, head, member) \
- for (pos = nl_list_entry((head)->next, typeof(*pos), member), \
- n = nl_list_entry(pos->member.next, typeof(*pos), member); \
+ for (pos = nl_list_entry((head)->next, __typeof__(*pos), member), \
+ n = nl_list_entry(pos->member.next, __typeof__(*pos), member); \
&(pos)->member != (head); \
- pos = n, n = nl_list_entry(n->member.next, typeof(*n), member))
+ pos = n, n = nl_list_entry(n->member.next, __typeof__(*n), member))
#define nl_init_list_head(head) \
do { (head)->next = (head); (head)->prev = (head); } while (0)
diff --git a/include/netlink/msg.h b/include/netlink/msg.h
index f3d50ae2..51d9aebc 100644
--- a/include/netlink/msg.h
+++ b/include/netlink/msg.h
@@ -20,6 +20,8 @@
extern "C" {
#endif
+struct nlmsghdr;
+
#define NL_DONTPAD 0
/**
@@ -64,10 +66,10 @@ extern int nlmsg_valid_hdr(const struct nlmsghdr *, int);
extern int nlmsg_ok(const struct nlmsghdr *, int);
extern struct nlmsghdr * nlmsg_next(struct nlmsghdr *, int *);
extern int nlmsg_parse(struct nlmsghdr *, int, struct nlattr **,
- int, struct nla_policy *);
+ int, const struct nla_policy *);
extern struct nlattr * nlmsg_find_attr(struct nlmsghdr *, int, int);
extern int nlmsg_validate(struct nlmsghdr *, int, int,
- struct nla_policy *);
+ const struct nla_policy *);
extern struct nl_msg * nlmsg_alloc(void);
extern struct nl_msg * nlmsg_alloc_size(size_t);
diff --git a/include/netlink/netfilter/exp.h b/include/netlink/netfilter/exp.h
index 4e950147..736af24e 100644
--- a/include/netlink/netfilter/exp.h
+++ b/include/netlink/netfilter/exp.h
@@ -82,7 +82,10 @@ extern uint16_t nfnl_exp_get_zone(const struct nfnl_exp *);
extern void nfnl_exp_set_flags(struct nfnl_exp *, uint32_t);
extern int nfnl_exp_test_flags(const struct nfnl_exp *);
+extern void nfnl_exp_unset_flags(struct nfnl_exp *exp, uint32_t flags);
extern uint32_t nfnl_exp_get_flags(const struct nfnl_exp *);
+extern char * nfnl_exp_flags2str(int flags, char *buf, size_t len);
+int nfnl_exp_str2flags(const char *name);
extern void nfnl_exp_set_class(struct nfnl_exp *, uint32_t);
extern int nfnl_exp_test_class(const struct nfnl_exp *);
diff --git a/include/netlink/netfilter/log.h b/include/netlink/netfilter/log.h
index 2002fa8b..e48eddff 100644
--- a/include/netlink/netfilter/log.h
+++ b/include/netlink/netfilter/log.h
@@ -58,7 +58,7 @@ extern enum nfnl_log_copy_mode nfnl_log_get_copy_mode(const struct nfnl_log *);
extern char * nfnl_log_copy_mode2str(enum nfnl_log_copy_mode,
char *, size_t);
-extern enum nfnl_log_copy_mode nfnl_log_str2copy_mode(const char *);
+extern int nfnl_log_str2copy_mode(const char *);
extern void nfnl_log_set_copy_range(struct nfnl_log *, uint32_t);
extern int nfnl_log_test_copy_range(const struct nfnl_log *);
diff --git a/include/netlink/netfilter/queue.h b/include/netlink/netfilter/queue.h
index 664610db..224d4696 100644
--- a/include/netlink/netfilter/queue.h
+++ b/include/netlink/netfilter/queue.h
@@ -54,7 +54,7 @@ extern enum nfnl_queue_copy_mode nfnl_queue_get_copy_mode(const struct nfnl_queu
extern char * nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode,
char *, size_t);
-extern enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *);
+extern int nfnl_queue_str2copy_mode(const char *);
extern void nfnl_queue_set_copy_range(struct nfnl_queue *,
uint32_t);
diff --git a/include/netlink/netfilter/queue_msg.h b/include/netlink/netfilter/queue_msg.h
index 9befee7c..86f4b862 100644
--- a/include/netlink/netfilter/queue_msg.h
+++ b/include/netlink/netfilter/queue_msg.h
@@ -93,6 +93,8 @@ extern unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *);
extern struct nl_msg * nfnl_queue_msg_build_verdict(const struct nfnl_queue_msg *);
extern int nfnl_queue_msg_send_verdict(struct nl_sock *,
const struct nfnl_queue_msg *);
+
+extern struct nl_msg * nfnl_queue_msg_build_verdict_batch(const struct nfnl_queue_msg *msg);
extern int nfnl_queue_msg_send_verdict_batch(struct nl_sock *,
const struct nfnl_queue_msg *);
extern int nfnl_queue_msg_send_verdict_payload(struct nl_sock *,
diff --git a/include/netlink/netlink-compat.h b/include/netlink/netlink-compat.h
index 17ec9fc8..2839ed03 100644
--- a/include/netlink/netlink-compat.h
+++ b/include/netlink/netlink-compat.h
@@ -47,4 +47,8 @@ typedef unsigned short sa_family_t;
#define AF_LLC 26
#endif
+#ifndef AF_MPLS
+#define AF_MPLS 28
+#endif
+
#endif
diff --git a/include/netlink/netlink.h b/include/netlink/netlink.h
index 28dba06e..41d48c68 100644
--- a/include/netlink/netlink.h
+++ b/include/netlink/netlink.h
@@ -16,7 +16,7 @@
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
-#include <sys/poll.h>
+#include <poll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
@@ -38,6 +38,7 @@
extern "C" {
#endif
+struct nlmsghdr;
struct ucred;
struct nl_cache_ops;
struct nl_parser_param;
@@ -87,6 +88,11 @@ extern int nl_pickup(struct nl_sock *,
struct nlmsghdr *,
struct nl_parser_param *),
struct nl_object **);
+extern int nl_pickup_keep_syserr(struct nl_sock *sk,
+ int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+ struct nlmsghdr *, struct nl_parser_param *),
+ struct nl_object **result,
+ int *syserror);
/* Netlink Family Translations */
extern char * nl_nlfamily2str(int, char *, size_t);
extern int nl_str2nlfamily(const char *);
diff --git a/include/netlink/object.h b/include/netlink/object.h
index a95feda7..b0c32c98 100644
--- a/include/netlink/object.h
+++ b/include/netlink/object.h
@@ -43,6 +43,8 @@ extern int nl_object_identical(struct nl_object *,
struct nl_object *);
extern uint32_t nl_object_diff(struct nl_object *,
struct nl_object *);
+extern uint64_t nl_object_diff64(struct nl_object *,
+ struct nl_object *);
extern int nl_object_match_filter(struct nl_object *,
struct nl_object *);
extern char * nl_object_attrs2str(struct nl_object *,
diff --git a/include/netlink/route/act/gact.h b/include/netlink/route/act/gact.h
new file mode 100644
index 00000000..9538711b
--- /dev/null
+++ b/include/netlink/route/act/gact.h
@@ -0,0 +1,31 @@
+/*
+ * netlink/route/act/gact.h gact action
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2016 Sushma Sitaram <sushma.sitaram@intel.com>
+ */
+
+#ifndef NETLINK_GACT_H_
+#define NETLINK_GACT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/action.h>
+#include <linux/tc_act/tc_gact.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_gact_set_action(struct rtnl_act *act, int action);
+extern int rtnl_gact_get_action(struct rtnl_act *act);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/act/skbedit.h b/include/netlink/route/act/skbedit.h
new file mode 100644
index 00000000..69829e83
--- /dev/null
+++ b/include/netlink/route/act/skbedit.h
@@ -0,0 +1,37 @@
+/*
+ * netlink/route/act/skbedit.h skbedit action
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2015 Cong Wang <xiyou.wangcong@gmail.com>
+ */
+
+#ifndef NETLINK_SKBEDIT_H_
+#define NETLINK_SKBEDIT_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/action.h>
+#include <linux/tc_act/tc_skbedit.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_skbedit_set_action(struct rtnl_act *act, int action);
+extern int rtnl_skbedit_get_action(struct rtnl_act *act);
+extern int rtnl_skbedit_set_queue_mapping(struct rtnl_act *act, uint16_t index);
+extern int rtnl_skbedit_get_queue_mapping(struct rtnl_act *act, uint16_t *index);
+extern int rtnl_skbedit_set_mark(struct rtnl_act *act, uint32_t mark);
+extern int rtnl_skbedit_get_mark(struct rtnl_act *act, uint32_t *mark);
+extern int rtnl_skbedit_set_priority(struct rtnl_act *act, uint32_t prio);
+extern int rtnl_skbedit_get_priority(struct rtnl_act *act, uint32_t *prio);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/act/vlan.h b/include/netlink/route/act/vlan.h
new file mode 100644
index 00000000..3dcce7c7
--- /dev/null
+++ b/include/netlink/route/act/vlan.h
@@ -0,0 +1,38 @@
+/*
+ * netlink/route/act/vlan.h vlan action
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
+ */
+
+#ifndef NETLINK_VLAN_H_
+#define NETLINK_VLAN_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/action.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_vlan_set_mode(struct rtnl_act *act, int mode);
+extern int rtnl_vlan_get_mode(struct rtnl_act *act, int *out_mode);
+extern int rtnl_vlan_set_action(struct rtnl_act *act, int action);
+extern int rtnl_vlan_get_action(struct rtnl_act *act, int *out_action);
+extern int rtnl_vlan_set_protocol(struct rtnl_act *act, uint16_t protocol);
+extern int rtnl_vlan_get_protocol(struct rtnl_act *act, uint16_t *out_protocol);
+extern int rtnl_vlan_set_vlan_id(struct rtnl_act *act, uint16_t vid);
+extern int rtnl_vlan_get_vlan_id(struct rtnl_act *act, uint16_t *out_vid);
+extern int rtnl_vlan_set_vlan_prio(struct rtnl_act *act, uint8_t prio);
+extern int rtnl_vlan_get_vlan_prio(struct rtnl_act *act, uint8_t *out_prio);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETLINK_VLAN_H_ */
diff --git a/include/netlink/route/action.h b/include/netlink/route/action.h
index 054bdd87..7d4c1857 100644
--- a/include/netlink/route/action.h
+++ b/include/netlink/route/action.h
@@ -22,11 +22,13 @@ extern "C" {
#endif
extern struct rtnl_act *rtnl_act_alloc(void);
+extern struct rtnl_act *rtnl_act_next(struct rtnl_act *);
extern void rtnl_act_get(struct rtnl_act *);
extern void rtnl_act_put(struct rtnl_act *);
extern int rtnl_act_build_add_request(struct rtnl_act *, int,
struct nl_msg **);
extern int rtnl_act_add(struct nl_sock *, struct rtnl_act *, int);
+extern int rtnl_act_change(struct nl_sock *, struct rtnl_act *, int);
extern int rtnl_act_build_change_request(struct rtnl_act *, int,
struct nl_msg **);
diff --git a/include/netlink/route/class.h b/include/netlink/route/class.h
index e73b60a7..38333397 100644
--- a/include/netlink/route/class.h
+++ b/include/netlink/route/class.h
@@ -31,6 +31,9 @@ extern int rtnl_class_alloc_cache(struct nl_sock *, int,
extern struct rtnl_class *
rtnl_class_get(struct nl_cache *, int, uint32_t);
+extern struct rtnl_class *
+ rtnl_class_get_by_parent(struct nl_cache *, int, uint32_t);
+
extern struct rtnl_qdisc *
rtnl_class_leaf_qdisc(struct rtnl_class *,
struct nl_cache *);
diff --git a/include/netlink/route/classifier.h b/include/netlink/route/classifier.h
index a8c11798..18832ada 100644
--- a/include/netlink/route/classifier.h
+++ b/include/netlink/route/classifier.h
@@ -27,6 +27,8 @@ extern void rtnl_cls_put(struct rtnl_cls *);
extern int rtnl_cls_alloc_cache(struct nl_sock *, int, uint32_t,
struct nl_cache **);
+extern void rtnl_cls_cache_set_tc_params(struct nl_cache *, int, uint32_t);
+
extern int rtnl_cls_build_add_request(struct rtnl_cls *, int,
struct nl_msg **);
extern int rtnl_cls_add(struct nl_sock *, struct rtnl_cls *, int);
diff --git a/include/netlink/route/cls/basic.h b/include/netlink/route/cls/basic.h
index f00793ca..51232ae0 100644
--- a/include/netlink/route/cls/basic.h
+++ b/include/netlink/route/cls/basic.h
@@ -28,6 +28,7 @@ extern void rtnl_basic_set_ematch(struct rtnl_cls *,
extern struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *);
extern int rtnl_basic_add_action(struct rtnl_cls *, struct rtnl_act *);
extern int rtnl_basic_del_action(struct rtnl_cls *, struct rtnl_act *);
+extern struct rtnl_act* rtnl_basic_get_action(struct rtnl_cls *);
#ifdef __cplusplus
}
diff --git a/include/netlink/route/cls/ematch.h b/include/netlink/route/cls/ematch.h
index 13f9c323..f4dac1df 100644
--- a/include/netlink/route/cls/ematch.h
+++ b/include/netlink/route/cls/ematch.h
@@ -73,6 +73,8 @@ extern void rtnl_ematch_tree_free(struct rtnl_ematch_tree *);
extern void rtnl_ematch_tree_add(struct rtnl_ematch_tree *,
struct rtnl_ematch *);
+extern struct rtnl_ematch_tree *rtnl_ematch_tree_clone(struct rtnl_ematch_tree *);
+
extern int rtnl_ematch_parse_attr(struct nlattr *,
struct rtnl_ematch_tree **);
extern int rtnl_ematch_fill_attr(struct nl_msg *, int,
diff --git a/include/netlink/route/cls/ematch/cmp.h b/include/netlink/route/cls/ematch/cmp.h
index 308113e0..7afb7923 100644
--- a/include/netlink/route/cls/ematch/cmp.h
+++ b/include/netlink/route/cls/ematch/cmp.h
@@ -20,6 +20,8 @@
extern "C" {
#endif
+struct tcf_em_cmp;
+
extern void rtnl_ematch_cmp_set(struct rtnl_ematch *,
struct tcf_em_cmp *);
extern struct tcf_em_cmp *
diff --git a/include/netlink/route/cls/matchall.h b/include/netlink/route/cls/matchall.h
new file mode 100644
index 00000000..19556943
--- /dev/null
+++ b/include/netlink/route/cls/matchall.h
@@ -0,0 +1,36 @@
+/*
+ * netlink/route/cls/matchall.h matchall classifier
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2017 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
+ */
+
+#ifndef NETLINK_MATCHALL_H_
+#define NETLINK_MATCHALL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/action.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_mall_set_classid(struct rtnl_cls *, uint32_t);
+extern int rtnl_mall_get_classid(struct rtnl_cls *, uint32_t *);
+extern int rtnl_mall_set_flags(struct rtnl_cls *, uint32_t);
+extern int rtnl_mall_get_flags(struct rtnl_cls *, uint32_t *);
+extern int rtnl_mall_append_action(struct rtnl_cls *, struct rtnl_act *);
+extern struct rtnl_act *rtnl_mall_get_first_action(struct rtnl_cls *);
+extern int rtnl_mall_del_action(struct rtnl_cls *, struct rtnl_act *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/cls/u32.h b/include/netlink/route/cls/u32.h
index f35d37a4..2443f513 100644
--- a/include/netlink/route/cls/u32.h
+++ b/include/netlink/route/cls/u32.h
@@ -23,13 +23,17 @@ extern "C" {
extern void rtnl_u32_set_handle(struct rtnl_cls *, int, int, int);
extern int rtnl_u32_set_classid(struct rtnl_cls *, uint32_t);
+extern int rtnl_u32_get_classid(struct rtnl_cls *, uint32_t *);
extern int rtnl_u32_set_divisor(struct rtnl_cls *, uint32_t);
extern int rtnl_u32_set_link(struct rtnl_cls *, uint32_t);
extern int rtnl_u32_set_hashtable(struct rtnl_cls *, uint32_t);
extern int rtnl_u32_set_hashmask(struct rtnl_cls *, uint32_t, uint32_t);
+extern int rtnl_u32_set_selector(struct rtnl_cls *, int, uint32_t, char, uint16_t, char);
extern int rtnl_u32_set_cls_terminal(struct rtnl_cls *);
extern int rtnl_u32_set_flags(struct rtnl_cls *, int);
+extern int rtnl_u32_add_mark(struct rtnl_cls *, uint32_t, uint32_t);
+extern int rtnl_u32_del_mark(struct rtnl_cls *);
extern int rtnl_u32_add_key(struct rtnl_cls *, uint32_t, uint32_t,
int, int);
extern int rtnl_u32_get_key(struct rtnl_cls *, uint8_t, uint32_t *, uint32_t *,
@@ -46,6 +50,7 @@ extern int rtnl_u32_add_key_in6_addr(struct rtnl_cls *, const struct in6_addr *,
uint8_t, int, int);
extern int rtnl_u32_add_action(struct rtnl_cls *, struct rtnl_act *);
extern int rtnl_u32_del_action(struct rtnl_cls *, struct rtnl_act *);
+extern struct rtnl_act* rtnl_u32_get_action(struct rtnl_cls *);
#ifdef __cplusplus
}
diff --git a/include/netlink/route/link.h b/include/netlink/route/link.h
index a7aa88b7..8fd0994f 100644
--- a/include/netlink/route/link.h
+++ b/include/netlink/route/link.h
@@ -15,7 +15,6 @@
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/addr.h>
-#include <linux/if.h>
#include <sys/types.h>
#ifdef __cplusplus
@@ -99,6 +98,7 @@ typedef enum {
RTNL_LINK_IP6_ECT1PKTS, /*!< IPv6 SNMP InECT1Pkts */
RTNL_LINK_IP6_ECT0PKTS, /*!< IPv6 SNMP InECT0Pkts */
RTNL_LINK_IP6_CEPKTS, /*!< IPv6 SNMP InCEPkts */
+ RTNL_LINK_RX_NOHANDLER, /*!< Received packets dropped on inactive device */
__RTNL_LINK_STATS_MAX,
} rtnl_link_stat_id_t;
@@ -110,6 +110,9 @@ extern struct rtnl_link *rtnl_link_alloc(void);
extern void rtnl_link_put(struct rtnl_link *);
extern int rtnl_link_alloc_cache(struct nl_sock *, int, struct nl_cache **);
+extern int rtnl_link_alloc_cache_flags(struct nl_sock *, int,
+ struct nl_cache **,
+ unsigned int flags);
extern struct rtnl_link *rtnl_link_get(struct nl_cache *, int);
extern struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *, const char *);
@@ -197,12 +200,17 @@ extern int rtnl_link_get_master(struct rtnl_link *);
extern void rtnl_link_set_carrier(struct rtnl_link *, uint8_t);
extern uint8_t rtnl_link_get_carrier(struct rtnl_link *);
+extern int rtnl_link_get_carrier_changes(struct rtnl_link *, uint32_t *);
+
extern void rtnl_link_set_operstate(struct rtnl_link *, uint8_t);
extern uint8_t rtnl_link_get_operstate(struct rtnl_link *);
extern void rtnl_link_set_linkmode(struct rtnl_link *, uint8_t);
extern uint8_t rtnl_link_get_linkmode(struct rtnl_link *);
+int rtnl_link_set_link_netnsid(struct rtnl_link *link, int32_t link_netnsid);
+int rtnl_link_get_link_netnsid(const struct rtnl_link *link, int32_t *out_link_netnsid);
+
extern const char * rtnl_link_get_ifalias(struct rtnl_link *);
extern void rtnl_link_set_ifalias(struct rtnl_link *, const char *);
@@ -215,6 +223,9 @@ extern int rtnl_link_set_stat(struct rtnl_link *, rtnl_link_stat_id_t,
extern int rtnl_link_set_type(struct rtnl_link *, const char *);
extern char * rtnl_link_get_type(struct rtnl_link *);
+extern int rtnl_link_set_slave_type(struct rtnl_link *, const char *);
+extern const char * rtnl_link_get_slave_type(const struct rtnl_link *);
+
extern void rtnl_link_set_promiscuity(struct rtnl_link *, uint32_t);
extern uint32_t rtnl_link_get_promiscuity(struct rtnl_link *);
@@ -224,8 +235,16 @@ extern uint32_t rtnl_link_get_num_tx_queues(struct rtnl_link *);
extern void rtnl_link_set_num_rx_queues(struct rtnl_link *, uint32_t);
extern uint32_t rtnl_link_get_num_rx_queues(struct rtnl_link *);
+extern int rtnl_link_get_gso_max_segs(struct rtnl_link *, uint32_t *);
+
+extern int rtnl_link_get_gso_max_size(struct rtnl_link *, uint32_t *);
+
extern struct nl_data * rtnl_link_get_phys_port_id(struct rtnl_link *);
+extern char* rtnl_link_get_phys_port_name(struct rtnl_link *);
+
+extern struct nl_data * rtnl_link_get_phys_switch_id(struct rtnl_link *);
+
extern void rtnl_link_set_ns_fd(struct rtnl_link *, int);
extern int rtnl_link_get_ns_fd(struct rtnl_link *);
extern void rtnl_link_set_ns_pid(struct rtnl_link *, pid_t);
@@ -239,6 +258,10 @@ extern int rtnl_link_release(struct nl_sock *, struct rtnl_link *);
extern int rtnl_link_fill_info(struct nl_msg *, struct rtnl_link *);
extern int rtnl_link_info_parse(struct rtnl_link *, struct nlattr **);
+extern int rtnl_link_has_vf_list(struct rtnl_link *);
+extern void rtnl_link_set_vf_list(struct rtnl_link *);
+extern void rtnl_link_unset_vf_list(struct rtnl_link *);
+
/* deprecated */
extern int rtnl_link_set_info_type(struct rtnl_link *, const char *) __attribute__((deprecated));
diff --git a/include/netlink/route/link/bridge.h b/include/netlink/route/link/bridge.h
index 16a4505f..f2e16e34 100644
--- a/include/netlink/route/link/bridge.h
+++ b/include/netlink/route/link/bridge.h
@@ -19,6 +19,16 @@
extern "C" {
#endif
+#define RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX 4096
+#define RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN (RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX / 32)
+
+struct rtnl_link_bridge_vlan
+{
+ uint16_t pvid;
+ uint32_t vlan_bitmap[RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN];
+ uint32_t untagged_bitmap[RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN];
+};
+
/**
* Bridge flags
* @ingroup bridge
@@ -28,8 +38,16 @@ enum rtnl_link_bridge_flags {
RTNL_BRIDGE_BPDU_GUARD = 0x0002,
RTNL_BRIDGE_ROOT_BLOCK = 0x0004,
RTNL_BRIDGE_FAST_LEAVE = 0x0008,
+ RTNL_BRIDGE_UNICAST_FLOOD = 0x0010,
+ RTNL_BRIDGE_LEARNING = 0x0020,
+ RTNL_BRIDGE_LEARNING_SYNC = 0x0040,
};
+#define RTNL_BRIDGE_HWMODE_VEB BRIDGE_MODE_VEB
+#define RTNL_BRIDGE_HWMODE_VEPA BRIDGE_MODE_VEPA
+#define RTNL_BRIDGE_HWMODE_MAX BRIDGE_MODE_VEPA
+#define RTNL_BRIDGE_HWMODE_UNDEF BRIDGE_MODE_UNDEF
+
extern struct rtnl_link *rtnl_link_bridge_alloc(void);
extern int rtnl_link_is_bridge(struct rtnl_link *);
@@ -48,10 +66,26 @@ extern int rtnl_link_bridge_unset_flags(struct rtnl_link *, unsigned int);
extern int rtnl_link_bridge_set_flags(struct rtnl_link *, unsigned int);
extern int rtnl_link_bridge_get_flags(struct rtnl_link *);
+extern int rtnl_link_bridge_set_self(struct rtnl_link *);
+
+extern int rtnl_link_bridge_get_hwmode(struct rtnl_link *, uint16_t *);
+extern int rtnl_link_bridge_set_hwmode(struct rtnl_link *, uint16_t);
+
extern char * rtnl_link_bridge_flags2str(int, char *, size_t);
extern int rtnl_link_bridge_str2flags(const char *);
+extern char * rtnl_link_bridge_portstate2str(int, char *, size_t);
+extern int rtnl_link_bridge_str2portstate(const char *);
+
+extern char * rtnl_link_bridge_hwmode2str(uint16_t, char *, size_t);
+extern uint16_t rtnl_link_bridge_str2hwmode(const char *);
+
extern int rtnl_link_bridge_add(struct nl_sock *sk, const char *name);
+
+extern int rtnl_link_bridge_pvid(struct rtnl_link *link);
+extern int rtnl_link_bridge_has_vlan(struct rtnl_link *link);
+
+extern struct rtnl_link_bridge_vlan *rtnl_link_bridge_get_port_vlan(struct rtnl_link *link);
#ifdef __cplusplus
}
#endif
diff --git a/include/netlink/route/link/can.h b/include/netlink/route/link/can.h
index 61c9f47e..1979a714 100644
--- a/include/netlink/route/link/can.h
+++ b/include/netlink/route/link/can.h
@@ -20,6 +20,10 @@
extern "C" {
#endif
+struct can_bittiming_const;
+struct can_bittiming;
+struct can_berr_counter;
+
extern int rtnl_link_is_can(struct rtnl_link *link);
extern char *rtnl_link_can_ctrlmode2str(int, char *, size_t);
diff --git a/include/netlink/route/link/geneve.h b/include/netlink/route/link/geneve.h
new file mode 100644
index 00000000..aaba1f90
--- /dev/null
+++ b/include/netlink/route/link/geneve.h
@@ -0,0 +1,60 @@
+/*
+ * netlink/route/link/geneve.h GENEVE interface
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ */
+
+#ifndef NETLINK_LINK_GENEVE_H_
+#define NETLINK_LINK_GENEVE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTNL_GENEVE_ID_MAX 16777215
+
+#define RTNL_LINK_GENEVE_F_COLLECT_METADATA (1<<0)
+
+extern struct rtnl_link *rtnl_link_geneve_alloc(void);
+extern int rtnl_link_is_geneve(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_id(struct rtnl_link *, uint32_t);
+extern int rtnl_link_geneve_get_id(struct rtnl_link *, uint32_t *);
+
+extern int rtnl_link_geneve_set_remote(struct rtnl_link *, struct nl_addr *);
+extern int rtnl_link_geneve_get_remote(struct rtnl_link *, struct nl_addr **);
+
+extern int rtnl_link_geneve_set_ttl(struct rtnl_link *, uint8_t);
+extern int rtnl_link_geneve_get_ttl(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_tos(struct rtnl_link *, uint8_t);
+extern int rtnl_link_geneve_get_tos(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_port(struct rtnl_link *, uint32_t);
+extern int rtnl_link_geneve_get_port(struct rtnl_link *, uint32_t *);
+
+extern int rtnl_link_geneve_set_label(struct rtnl_link *, uint32_t);
+extern int rtnl_link_geneve_get_label(struct rtnl_link *, uint32_t *);
+
+extern int rtnl_link_geneve_set_udp_csum(struct rtnl_link *, uint8_t);
+extern int rtnl_link_geneve_get_udp_csum(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_udp_zero_csum6_tx(struct rtnl_link *, uint8_t);
+extern int rtnl_link_geneve_get_udp_zero_csum6_tx(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_udp_zero_csum6_rx(struct rtnl_link *, uint8_t);
+extern int rtnl_link_geneve_get_udp_zero_csum6_rx(struct rtnl_link *);
+
+extern int rtnl_link_geneve_set_flags(struct rtnl_link *, uint8_t flags, int enable);
+extern int rtnl_link_geneve_get_flags(struct rtnl_link *, uint8_t *flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link/inet6.h b/include/netlink/route/link/inet6.h
new file mode 100644
index 00000000..666a9b83
--- /dev/null
+++ b/include/netlink/route/link/inet6.h
@@ -0,0 +1,53 @@
+/*
+ * netlink/route/link/inet6.h INET6 Link Module
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2014 Dan Williams <dcbw@redhat.com>
+ */
+
+#ifndef NETLINK_LINK_INET6_H_
+#define NETLINK_LINK_INET6_H_
+
+#include <netlink/netlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const char * rtnl_link_inet6_addrgenmode2str (uint8_t mode,
+ char *buf,
+ size_t len);
+
+uint8_t rtnl_link_inet6_str2addrgenmode (const char *mode);
+
+extern int rtnl_link_inet6_get_token(struct rtnl_link *,
+ struct nl_addr **);
+
+extern int rtnl_link_inet6_set_token(struct rtnl_link *,
+ struct nl_addr *);
+
+extern int rtnl_link_inet6_get_addr_gen_mode(struct rtnl_link *,
+ uint8_t *);
+
+extern int rtnl_link_inet6_set_addr_gen_mode(struct rtnl_link *,
+ uint8_t);
+
+extern int rtnl_link_inet6_get_flags(struct rtnl_link *,
+ uint32_t *);
+
+extern int rtnl_link_inet6_set_flags(struct rtnl_link *,
+ uint32_t);
+
+/* Link Flags Translations */
+extern char * rtnl_link_inet6_flags2str(int, char *, size_t);
+extern int rtnl_link_inet6_str2flags(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link/ip6tnl.h b/include/netlink/route/link/ip6tnl.h
index 7e0c2958..87ab164f 100644
--- a/include/netlink/route/link/ip6tnl.h
+++ b/include/netlink/route/link/ip6tnl.h
@@ -22,6 +22,8 @@ extern "C" {
extern struct rtnl_link *rtnl_link_ip6_tnl_alloc(void);
extern int rtnl_link_ip6_tnl_add(struct nl_sock *sk, const char *name);
+ extern int rtnl_link_is_ip6_tnl(struct rtnl_link *link);
+
extern int rtnl_link_ip6_tnl_set_link(struct rtnl_link *link, uint32_t index);
extern uint32_t rtnl_link_ip6_tnl_get_link(struct rtnl_link *link);
@@ -49,7 +51,7 @@ extern "C" {
extern int rtnl_link_ip6_tnl_set_proto(struct rtnl_link *link, uint8_t proto);
extern uint8_t rtnl_link_ip6_tnl_get_proto(struct rtnl_link *link);
-#ifdef _cplusplus
+#ifdef __cplusplus
}
#endif
diff --git a/include/netlink/route/link/ipgre.h b/include/netlink/route/link/ipgre.h
index 5a0a295a..4c5f86b0 100644
--- a/include/netlink/route/link/ipgre.h
+++ b/include/netlink/route/link/ipgre.h
@@ -19,8 +19,13 @@
extern "C" {
#endif
+ extern int rtnl_link_is_ipgre(struct rtnl_link *link);
+ extern int rtnl_link_is_ipgretap(struct rtnl_link *link);
+
extern struct rtnl_link *rtnl_link_ipgre_alloc(void);
+ extern struct rtnl_link *rtnl_link_ipgretap_alloc(void);
extern int rtnl_link_ipgre_add(struct nl_sock *sk, const char *name);
+ extern int rtnl_link_ipgretap_add(struct nl_sock *sk, const char *name);
extern int rtnl_link_ipgre_set_link(struct rtnl_link *link, uint32_t index);
extern uint32_t rtnl_link_ipgre_get_link(struct rtnl_link *link);
diff --git a/include/netlink/route/link/ipip.h b/include/netlink/route/link/ipip.h
index ccadb874..a7f51583 100644
--- a/include/netlink/route/link/ipip.h
+++ b/include/netlink/route/link/ipip.h
@@ -18,10 +18,11 @@
#ifdef __cplusplus
extern "C" {
#endif
-
extern struct rtnl_link *rtnl_link_ipip_alloc(void);
extern int rtnl_link_ipip_add(struct nl_sock *sk, const char *name);
+ extern int rtnl_link_is_ipip(struct rtnl_link *link);
+
extern uint32_t rtnl_link_ipip_get_link(struct rtnl_link *link);
extern int rtnl_link_ipip_set_link(struct rtnl_link *link, uint32_t index);
diff --git a/include/netlink/route/link/ipvlan.h b/include/netlink/route/link/ipvlan.h
new file mode 100644
index 00000000..d13bcbbc
--- /dev/null
+++ b/include/netlink/route/link/ipvlan.h
@@ -0,0 +1,37 @@
+/*
+ * netlink/route/link/ipvlan.h IPVLAN interface
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2015 Cong Wang <cwang@twopensource.com>
+ */
+
+#ifndef NETLINK_LINK_IPVLAN_H_
+#define NETLINK_LINK_IPVLAN_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct rtnl_link *rtnl_link_ipvlan_alloc(void);
+
+extern int rtnl_link_is_ipvlan(struct rtnl_link *);
+
+extern char * rtnl_link_ipvlan_mode2str(int, char *, size_t);
+extern int rtnl_link_ipvlan_str2mode(const char *);
+
+extern int rtnl_link_ipvlan_set_mode(struct rtnl_link *,
+ uint16_t);
+extern int rtnl_link_ipvlan_get_mode(struct rtnl_link *, uint16_t *out_mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link/ipvti.h b/include/netlink/route/link/ipvti.h
index a3e7bbad..c97e57f8 100644
--- a/include/netlink/route/link/ipvti.h
+++ b/include/netlink/route/link/ipvti.h
@@ -21,20 +21,22 @@ extern "C" {
extern struct rtnl_link *rtnl_link_ipvti_alloc(void);
extern int rtnl_link_ipvti_add(struct nl_sock *sk, const char *name);
+ extern int rtnl_link_is_ipvti(struct rtnl_link *link);
+
extern int rtnl_link_ipvti_set_link(struct rtnl_link *link, uint32_t index);
extern uint32_t rtnl_link_ipvti_get_link(struct rtnl_link *link);
extern int rtnl_link_ipvti_set_ikey(struct rtnl_link *link, uint32_t ikey);
- extern uint32_t rtnl_link_get_ikey(struct rtnl_link *link);
+ extern uint32_t rtnl_link_ipvti_get_ikey(struct rtnl_link *link);
extern int rtnl_link_ipvti_set_okey(struct rtnl_link *link, uint32_t okey);
- extern uint32_t rtnl_link_get_okey(struct rtnl_link *link);
+ extern uint32_t rtnl_link_ipvti_get_okey(struct rtnl_link *link);
extern int rtnl_link_ipvti_set_local(struct rtnl_link *link, uint32_t addr);
- extern uint32_t rtnl_link_get_local(struct rtnl_link *link);
+ extern uint32_t rtnl_link_ipvti_get_local(struct rtnl_link *link);
extern int rtnl_link_ipvti_set_remote(struct rtnl_link *link, uint32_t addr);
- extern uint32_t rtnl_link_get_remote(struct rtnl_link *link);
+ extern uint32_t rtnl_link_ipvti_get_remote(struct rtnl_link *link);
#ifdef __cplusplus
}
diff --git a/include/netlink/route/link/macsec.h b/include/netlink/route/link/macsec.h
new file mode 100644
index 00000000..ace4de2d
--- /dev/null
+++ b/include/netlink/route/link/macsec.h
@@ -0,0 +1,75 @@
+/*
+ * netlink/route/link/macsec.h MACsec Link Info
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2016 Sabrina Dubroca <sd@queasysnail.net>
+ */
+
+#ifndef NETLINK_LINK_MACSEC_H_
+#define NETLINK_LINK_MACSEC_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+#include <linux/if_link.h>
+#include <linux/if_macsec.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum macsec_validation_type;
+
+struct rtnl_link *rtnl_link_macsec_alloc(void);
+
+int rtnl_link_macsec_set_sci(struct rtnl_link *, uint64_t);
+int rtnl_link_macsec_get_sci(struct rtnl_link *, uint64_t *);
+
+int rtnl_link_macsec_set_port(struct rtnl_link *, uint16_t);
+int rtnl_link_macsec_get_port(struct rtnl_link *, uint16_t *);
+
+int rtnl_link_macsec_set_cipher_suite(struct rtnl_link *, uint64_t);
+int rtnl_link_macsec_get_cipher_suite(struct rtnl_link *, uint64_t *);
+
+int rtnl_link_macsec_set_icv_len(struct rtnl_link *, uint16_t);
+int rtnl_link_macsec_get_icv_len(struct rtnl_link *, uint16_t *);
+
+int rtnl_link_macsec_set_protect(struct rtnl_link *, uint8_t);
+int rtnl_link_macsec_get_protect(struct rtnl_link *, uint8_t *);
+
+int rtnl_link_macsec_set_encrypt(struct rtnl_link *, uint8_t);
+int rtnl_link_macsec_get_encrypt(struct rtnl_link *, uint8_t *);
+
+int rtnl_link_macsec_set_encoding_sa(struct rtnl_link *, uint8_t);
+int rtnl_link_macsec_get_encoding_sa(struct rtnl_link *, uint8_t *);
+
+int rtnl_link_macsec_set_validation_type(struct rtnl_link *,
+ enum macsec_validation_type);
+int rtnl_link_macsec_get_validation_type(struct rtnl_link *,
+ enum macsec_validation_type *);
+
+int rtnl_link_macsec_set_replay_protect(struct rtnl_link *, uint8_t);
+int rtnl_link_macsec_get_replay_protect(struct rtnl_link *, uint8_t *);
+
+int rtnl_link_macsec_set_window(struct rtnl_link *, uint32_t);
+int rtnl_link_macsec_get_window(struct rtnl_link *, uint32_t *);
+
+int rtnl_link_macsec_set_send_sci(struct rtnl_link *, uint8_t);
+int rtnl_link_macsec_get_send_sci(struct rtnl_link *, uint8_t *);
+
+int rtnl_link_macsec_set_end_station(struct rtnl_link *, uint8_t);
+int rtnl_link_macsec_get_end_station(struct rtnl_link *, uint8_t *);
+
+int rtnl_link_macsec_set_scb(struct rtnl_link *, uint8_t);
+int rtnl_link_macsec_get_scb(struct rtnl_link *, uint8_t *);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link/macvlan.h b/include/netlink/route/link/macvlan.h
index 2207c534..15a6cc1c 100644
--- a/include/netlink/route/link/macvlan.h
+++ b/include/netlink/route/link/macvlan.h
@@ -29,6 +29,9 @@ extern int rtnl_link_macvlan_str2mode(const char *);
extern char * rtnl_link_macvlan_flags2str(int, char *, size_t);
extern int rtnl_link_macvlan_str2flags(const char *);
+extern char * rtnl_link_macvlan_macmode2str(int, char *, size_t);
+extern int rtnl_link_macvlan_str2macmode(const char *);
+
extern int rtnl_link_macvlan_set_mode(struct rtnl_link *,
uint32_t);
extern uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *);
@@ -39,6 +42,21 @@ extern int rtnl_link_macvlan_unset_flags(struct rtnl_link *,
uint16_t);
extern uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *);
+extern int rtnl_link_macvlan_set_macmode(struct rtnl_link *,
+ uint32_t);
+extern int rtnl_link_macvlan_get_macmode(struct rtnl_link *link,
+ uint32_t *out_macmode);
+
+extern int rtnl_link_macvlan_count_macaddr(struct rtnl_link *link,
+ uint32_t *out_count);
+extern int rtnl_link_macvlan_get_macaddr(struct rtnl_link *link,
+ uint32_t idx,
+ const struct nl_addr **addr);
+extern int rtnl_link_macvlan_add_macaddr(struct rtnl_link *link,
+ struct nl_addr *addr);
+extern int rtnl_link_macvlan_del_macaddr(struct rtnl_link *link,
+ struct nl_addr *addr);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/netlink/route/link/macvtap.h b/include/netlink/route/link/macvtap.h
new file mode 100644
index 00000000..affcddc7
--- /dev/null
+++ b/include/netlink/route/link/macvtap.h
@@ -0,0 +1,46 @@
+/*
+ * netlink/route/link/macvtap.h MACVTAP interface
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2015 Beniamino Galvani <bgalvani@redhat.com>
+ */
+
+#ifndef NETLINK_LINK_MACVTAP_H_
+#define NETLINK_LINK_MACVTAP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct rtnl_link *rtnl_link_macvtap_alloc(void);
+
+extern int rtnl_link_is_macvtap(struct rtnl_link *);
+
+extern char * rtnl_link_macvtap_mode2str(int, char *, size_t);
+extern int rtnl_link_macvtap_str2mode(const char *);
+
+extern char * rtnl_link_macvtap_flags2str(int, char *, size_t);
+extern int rtnl_link_macvtap_str2flags(const char *);
+
+extern int rtnl_link_macvtap_set_mode(struct rtnl_link *,
+ uint32_t);
+extern uint32_t rtnl_link_macvtap_get_mode(struct rtnl_link *);
+
+extern int rtnl_link_macvtap_set_flags(struct rtnl_link *,
+ uint16_t);
+extern int rtnl_link_macvtap_unset_flags(struct rtnl_link *,
+ uint16_t);
+extern uint16_t rtnl_link_macvtap_get_flags(struct rtnl_link *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link/ppp.h b/include/netlink/route/link/ppp.h
new file mode 100644
index 00000000..4ff811d1
--- /dev/null
+++ b/include/netlink/route/link/ppp.h
@@ -0,0 +1,30 @@
+/*
+ * netlink/route/link/ppp.h PPP Interface
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2016 Jonas Johansson <jonasj76@gmail.com>
+ */
+
+#ifndef NETLINK_LINK_PPP_H_
+#define NETLINK_LINK_PPP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct rtnl_link *rtnl_link_ppp_alloc(void);
+extern int rtnl_link_ppp_set_fd(struct rtnl_link *, int32_t);
+extern int rtnl_link_ppp_get_fd(struct rtnl_link *, int32_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link/sit.h b/include/netlink/route/link/sit.h
index 84dc44aa..d6f58519 100644
--- a/include/netlink/route/link/sit.h
+++ b/include/netlink/route/link/sit.h
@@ -22,11 +22,13 @@ extern "C" {
extern struct rtnl_link *rtnl_link_sit_alloc(void);
extern int rtnl_link_sit_add(struct nl_sock *sk, const char *name);
+ extern int rtnl_link_is_sit(struct rtnl_link *link);
+
extern int rtnl_link_sit_set_link(struct rtnl_link *link, uint32_t index);
extern uint32_t rtnl_link_sit_get_link(struct rtnl_link *link);
extern int rtnl_link_sit_set_local(struct rtnl_link *link, uint32_t addr);
- extern uint32_t rtnl_link_get_sit_local(struct rtnl_link *link);
+ extern uint32_t rtnl_link_sit_get_local(struct rtnl_link *link);
extern int rtnl_link_sit_set_remote(struct rtnl_link *link, uint32_t addr);
extern uint32_t rtnl_link_sit_get_remote(struct rtnl_link *link);
@@ -44,9 +46,21 @@ extern "C" {
extern uint16_t rtnl_link_sit_get_flags(struct rtnl_link *link);
int rtnl_link_sit_set_proto(struct rtnl_link *link, uint8_t proto);
- uint8_t rtnl_link_get_proto(struct rtnl_link *link);
+ uint8_t rtnl_link_sit_get_proto(struct rtnl_link *link);
+
+ int rtnl_link_sit_set_ip6rd_prefix(struct rtnl_link *link, const struct in6_addr *prefix);
+ int rtnl_link_sit_get_ip6rd_prefix(const struct rtnl_link *link, struct in6_addr *prefix);
+
+ int rtnl_link_sit_set_ip6rd_prefixlen(struct rtnl_link *link, uint16_t prefixlen);
+ int rtnl_link_sit_get_ip6rd_prefixlen(struct rtnl_link *link, uint16_t *prefixlen);
-#ifdef _cplusplus
+ int rtnl_link_sit_set_ip6rd_relay_prefix(struct rtnl_link *link, uint32_t prefix);
+ int rtnl_link_sit_get_ip6rd_relay_prefix(const struct rtnl_link *link, uint32_t *prefix);
+
+ int rtnl_link_sit_set_ip6rd_relay_prefixlen(struct rtnl_link *link, uint16_t prefix);
+ int rtnl_link_sit_get_ip6rd_relay_prefixlen(struct rtnl_link *link, uint16_t *prefix);
+
+#ifdef __cplusplus
}
#endif
diff --git a/include/netlink/route/link/sriov.h b/include/netlink/route/link/sriov.h
new file mode 100644
index 00000000..3f7cacf7
--- /dev/null
+++ b/include/netlink/route/link/sriov.h
@@ -0,0 +1,145 @@
+/*
+ * include/netlink/route/link/sriov.h SRIOV VF Info
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2016 Intel Corp. All rights reserved.
+ * Copyright (c) 2016 Jef Oliver <jef.oliver@intel.com>
+ */
+
+#ifndef NETLINK_LINK_SRIOV_H_
+#define NETLINK_LINK_SRIOV_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define RTNL_VF_GUID_STR_LEN 23
+
+/**
+ * @ingroup sriov
+ */
+typedef enum {
+ RTNL_LINK_VF_RATE_API_UNSPEC, /*!< Unspecified API type */
+ RTNL_LINK_VF_RATE_API_OLD, /*!< Old Rate setting API */
+ RTNL_LINK_VF_RATE_API_NEW, /*!< New Rate setting API */
+ __RTNL_LINK_VF_RATE_API_MAX,
+} rtnl_link_rate_api_t;
+
+#define RTNL_LINK_VF_RATE_API_MAX (__RTNL_LINK_VF_RATE_API_MAX - 1)
+
+/**
+ * @ingroup sriov
+ */
+typedef enum {
+ RTNL_LINK_VF_STATS_RX_PACKETS, /*!< Packets Received */
+ RTNL_LINK_VF_STATS_TX_PACKETS, /*!< Packets Sent */
+ RTNL_LINK_VF_STATS_RX_BYTES, /*!< Bytes Recieved */
+ RTNL_LINK_VF_STATS_TX_BYTES, /*!< Bytes Sent */
+ RTNL_LINK_VF_STATS_BROADCAST, /*!< Broadcast packets received */
+ RTNL_LINK_VF_STATS_MULTICAST, /*!< Multicast packets received */
+ __RTNL_LINK_VF_STATS_MAX,
+} rtnl_link_vf_stats_t;
+
+#define RTNL_LINK_VF_STATS_MAX (__RTNL_LINK_VF_STATS_MAX - 1)
+
+/**
+ * @struct rtnl_link_vf sriov.h "netlink/route/link/sriov.h"
+ * @brief SRIOV VF object
+ * @ingroup sriov
+ *
+ * @copydoc private_struct
+ */
+struct rtnl_link_vf;
+
+/**
+ * @brief SRIOV VF VFLAN settings
+ * @ingroup sriov
+ */
+typedef struct nl_vf_vlan_info {
+ uint32_t vf_vlan; /*!< VLAN number */
+ uint32_t vf_vlan_qos; /*!< VLAN QOS value */
+ uint16_t vf_vlan_proto; /*!< VLAN protocol */
+} nl_vf_vlan_info_t;
+
+/**
+ * @brief SRIOV VF VLANs information
+ * @ingroup sriov
+ */
+typedef struct nl_vf_vlans {
+ int ce_refcnt; /*!< Reference counter. Don't change this value */
+ int size; /*!< Number of VLANs on the SRIOV VF */
+ nl_vf_vlan_info_t * vlans; /*!< nl_vf_vlan_info_t array of SRIOV VF VLANs */
+} nl_vf_vlans_t;
+
+/**
+ * @brief VF Rate information structure
+ * @ingroup sriov
+ */
+struct nl_vf_rate {
+ int api; /*!< rtnl_link_rate_api_t API Version to use */
+ uint32_t rate; /*!< Old API Max Rate in Mbps */
+ uint32_t max_tx_rate; /*!< New API Max Rate in Mbps */
+ uint32_t min_tx_rate; /*!< New API Mix Rate in Mbps */
+};
+
+extern int rtnl_link_vf_add(struct rtnl_link *, struct rtnl_link_vf *);
+extern struct rtnl_link_vf *rtnl_link_vf_alloc(void);
+extern void rtnl_link_vf_free(struct rtnl_link_vf *);
+extern struct rtnl_link_vf *rtnl_link_vf_get(struct rtnl_link *, uint32_t);
+extern void rtnl_link_vf_put(struct rtnl_link_vf *);
+
+extern int rtnl_link_vf_get_addr(struct rtnl_link_vf *, struct nl_addr **);
+extern void rtnl_link_vf_set_addr(struct rtnl_link_vf *, struct nl_addr *);
+
+extern void rtnl_link_vf_set_ib_node_guid(struct rtnl_link_vf *, uint64_t);
+extern void rtnl_link_vf_set_ib_port_guid(struct rtnl_link_vf *, uint64_t);
+
+extern int rtnl_link_vf_get_index(struct rtnl_link_vf *, uint32_t *);
+extern void rtnl_link_vf_set_index(struct rtnl_link_vf *, uint32_t);
+
+extern int rtnl_link_vf_get_linkstate(struct rtnl_link_vf *, uint32_t *);
+extern void rtnl_link_vf_set_linkstate(struct rtnl_link_vf *, uint32_t);
+
+extern int rtnl_link_vf_get_rate(struct rtnl_link_vf *, struct nl_vf_rate *);
+extern void rtnl_link_vf_set_rate(struct rtnl_link_vf *, struct nl_vf_rate *);
+
+extern int rtnl_link_vf_get_rss_query_en(struct rtnl_link_vf *, uint32_t *);
+extern void rtnl_link_vf_set_rss_query_en(struct rtnl_link_vf *, uint32_t);
+
+extern int rtnl_link_vf_get_spoofchk(struct rtnl_link_vf *, uint32_t *);
+extern void rtnl_link_vf_set_spoofchk(struct rtnl_link_vf *, uint32_t);
+
+extern int rtnl_link_vf_get_stat(struct rtnl_link_vf *, rtnl_link_vf_stats_t,
+ uint64_t *);
+
+extern int rtnl_link_vf_get_trust(struct rtnl_link_vf *, uint32_t *);
+extern void rtnl_link_vf_set_trust(struct rtnl_link_vf *, uint32_t);
+
+extern int rtnl_link_vf_get_vlans(struct rtnl_link_vf *, nl_vf_vlans_t **);
+extern void rtnl_link_vf_set_vlans(struct rtnl_link_vf *, nl_vf_vlans_t *);
+
+extern int rtnl_link_vf_vlan_alloc(nl_vf_vlans_t **, int);
+extern void rtnl_link_vf_vlan_free(nl_vf_vlans_t *vf_vlans);
+extern void rtnl_link_vf_vlan_put(nl_vf_vlans_t *);
+
+/* Utility functions */
+extern char *rtnl_link_vf_linkstate2str(uint32_t, char *, size_t);
+extern int rtnl_link_vf_str2linkstate(const char *);
+
+extern char *rtnl_link_vf_vlanproto2str(uint16_t, char *, size_t);
+extern int rtnl_link_vf_str2vlanproto(const char *);
+
+extern int rtnl_link_vf_str2guid(uint64_t *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link/vrf.h b/include/netlink/route/link/vrf.h
new file mode 100644
index 00000000..0a56d91e
--- /dev/null
+++ b/include/netlink/route/link/vrf.h
@@ -0,0 +1,32 @@
+/*
+ * netlink/route/link/vrf.h VRF interface
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2015 Cumulus Networks. All rights reserved.
+ * Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com>
+ */
+
+#ifndef NETLINK_LINK_VRF_H_
+#define NETLINK_LINK_VRF_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct rtnl_link *rtnl_link_vrf_alloc(void);
+extern int rtnl_link_is_vrf(struct rtnl_link *link);
+extern int rtnl_link_vrf_get_tableid(struct rtnl_link *link, uint32_t *id);
+extern int rtnl_link_vrf_set_tableid(struct rtnl_link *link, uint32_t id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/link/vxlan.h b/include/netlink/route/link/vxlan.h
index f7f7b609..a929a9fa 100644
--- a/include/netlink/route/link/vxlan.h
+++ b/include/netlink/route/link/vxlan.h
@@ -19,20 +19,31 @@
extern "C" {
#endif
+struct ifla_vxlan_port_range;
+
#define VXLAN_ID_MAX 16777215
+enum {
+ RTNL_LINK_VXLAN_F_GBP = 1 << 0,
+#define RTNL_LINK_VXLAN_F_GBP RTNL_LINK_VXLAN_F_GBP
+ RTNL_LINK_VXLAN_F_GPE = 1 << 1,
+#define RTNL_LINK_VXLAN_F_GPE RTNL_LINK_VXLAN_F_GPE
+ RTNL_LINK_VXLAN_F_REMCSUM_NOPARTIAL = 1 << 2,
+#define RTNL_LINK_VXLAN_F_REMCSUM_NOPARTIAL RTNL_LINK_VXLAN_F_REMCSUM_NOPARTIAL
+};
+
extern struct rtnl_link *rtnl_link_vxlan_alloc(void);
-extern int rtnl_link_is_vxlan(struct rtnl_link *);
+extern int rtnl_link_is_vxlan(struct rtnl_link *);
-extern int rtnl_link_vxlan_set_id(struct rtnl_link *, uint32_t);
-extern int rtnl_link_vxlan_get_id(struct rtnl_link *, uint32_t *);
+extern int rtnl_link_vxlan_set_id(struct rtnl_link *, uint32_t);
+extern int rtnl_link_vxlan_get_id(struct rtnl_link *, uint32_t *);
extern int rtnl_link_vxlan_set_group(struct rtnl_link *, struct nl_addr *);
extern int rtnl_link_vxlan_get_group(struct rtnl_link *, struct nl_addr **);
-extern int rtnl_link_vxlan_set_link(struct rtnl_link *, uint32_t);
-extern int rtnl_link_vxlan_get_link(struct rtnl_link *, uint32_t *);
+extern int rtnl_link_vxlan_set_link(struct rtnl_link *, uint32_t);
+extern int rtnl_link_vxlan_get_link(struct rtnl_link *, uint32_t *);
extern int rtnl_link_vxlan_set_local(struct rtnl_link *, struct nl_addr *);
extern int rtnl_link_vxlan_get_local(struct rtnl_link *, struct nl_addr **);
@@ -79,6 +90,33 @@ extern int rtnl_link_vxlan_get_l3miss(struct rtnl_link *);
extern int rtnl_link_vxlan_enable_l3miss(struct rtnl_link *);
extern int rtnl_link_vxlan_disable_l3miss(struct rtnl_link *);
+extern int rtnl_link_vxlan_set_port(struct rtnl_link *, uint32_t);
+extern int rtnl_link_vxlan_get_port(struct rtnl_link *, uint32_t *);
+
+extern int rtnl_link_vxlan_set_udp_csum(struct rtnl_link *, uint8_t);
+extern int rtnl_link_vxlan_get_udp_csum(struct rtnl_link *);
+
+extern int rtnl_link_vxlan_set_udp_zero_csum6_tx(struct rtnl_link *, uint8_t);
+extern int rtnl_link_vxlan_get_udp_zero_csum6_tx(struct rtnl_link *);
+
+extern int rtnl_link_vxlan_set_udp_zero_csum6_rx(struct rtnl_link *, uint8_t);
+extern int rtnl_link_vxlan_get_udp_zero_csum6_rx(struct rtnl_link *);
+
+extern int rtnl_link_vxlan_set_remcsum_tx(struct rtnl_link *, uint8_t);
+extern int rtnl_link_vxlan_get_remcsum_tx(struct rtnl_link *);
+
+extern int rtnl_link_vxlan_set_remcsum_rx(struct rtnl_link *, uint8_t);
+extern int rtnl_link_vxlan_get_remcsum_rx(struct rtnl_link *);
+
+extern int rtnl_link_vxlan_set_flags(struct rtnl_link *, uint32_t flags, int enable);
+extern int rtnl_link_vxlan_get_flags(struct rtnl_link *, uint32_t *out_flags);
+
+extern int rtnl_link_vxlan_set_collect_metadata(struct rtnl_link *, uint8_t);
+extern int rtnl_link_vxlan_get_collect_metadata(struct rtnl_link *);
+
+extern int rtnl_link_vxlan_set_label(struct rtnl_link *, uint32_t);
+extern int rtnl_link_vxlan_get_label(struct rtnl_link *, uint32_t *);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/netlink/route/link/xfrmi.h b/include/netlink/route/link/xfrmi.h
new file mode 100644
index 00000000..6e4cda7b
--- /dev/null
+++ b/include/netlink/route/link/xfrmi.h
@@ -0,0 +1,37 @@
+/*
+ * netlink/route/link/xfrmi.h XFRMI interface
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2019 Eyal Birger <eyal.birger@gmail.com>
+ *
+ * Based on netlink/route/link/ipvti.h
+ */
+
+#ifndef NETLINK_LINK_XFRMI_H_
+#define NETLINK_LINK_XFRMI_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ extern struct rtnl_link *rtnl_link_xfrmi_alloc(void);
+
+ extern int rtnl_link_is_xfrmi(struct rtnl_link *link);
+
+ extern int rtnl_link_xfrmi_set_link(struct rtnl_link *link, uint32_t index);
+ extern int rtnl_link_xfrmi_get_link(struct rtnl_link *link, uint32_t *out_link);
+
+ extern int rtnl_link_xfrmi_set_if_id(struct rtnl_link *link, uint32_t if_id);
+ extern int rtnl_link_xfrmi_get_if_id(struct rtnl_link *link, uint32_t *out_if_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/neighbour.h b/include/netlink/route/neighbour.h
index 1d1179b3..0f17b66e 100644
--- a/include/netlink/route/neighbour.h
+++ b/include/netlink/route/neighbour.h
@@ -26,8 +26,13 @@ extern struct rtnl_neigh *rtnl_neigh_alloc(void);
extern void rtnl_neigh_put(struct rtnl_neigh *);
extern int rtnl_neigh_alloc_cache(struct nl_sock *, struct nl_cache **);
+extern int rtnl_neigh_alloc_cache_flags(struct nl_sock *,
+ struct nl_cache **,
+ unsigned int);
extern struct rtnl_neigh *rtnl_neigh_get(struct nl_cache *, int,
struct nl_addr *);
+extern struct rtnl_neigh *rtnl_neigh_get_by_vlan(struct nl_cache *, int,
+ struct nl_addr *, int);
extern int rtnl_neigh_parse(struct nlmsghdr *, struct rtnl_neigh **);
@@ -74,6 +79,12 @@ extern int rtnl_neigh_get_type(struct rtnl_neigh *);
extern void rtnl_neigh_set_family(struct rtnl_neigh *, int);
extern int rtnl_neigh_get_family(struct rtnl_neigh *);
+extern void rtnl_neigh_set_vlan(struct rtnl_neigh *, int);
+extern int rtnl_neigh_get_vlan(struct rtnl_neigh *);
+
+extern void rtnl_neigh_set_master(struct rtnl_neigh *, int);
+extern int rtnl_neigh_get_master(struct rtnl_neigh *);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/netlink/route/neightbl.h b/include/netlink/route/neightbl.h
index 412c3e94..6c6c9a57 100644
--- a/include/netlink/route/neightbl.h
+++ b/include/netlink/route/neightbl.h
@@ -41,6 +41,7 @@ extern void rtnl_neightbl_set_family(struct rtnl_neightbl *, int);
extern void rtnl_neightbl_set_gc_tresh1(struct rtnl_neightbl *, int);
extern void rtnl_neightbl_set_gc_tresh2(struct rtnl_neightbl *, int);
extern void rtnl_neightbl_set_gc_tresh3(struct rtnl_neightbl *, int);
+extern void rtnl_neightbl_set_gc_interval(struct rtnl_neightbl *, uint64_t);
extern void rtnl_neightbl_set_name(struct rtnl_neightbl *, const char *);
extern void rtnl_neightbl_set_dev(struct rtnl_neightbl *, int);
extern void rtnl_neightbl_set_queue_len(struct rtnl_neightbl *, int);
diff --git a/include/netlink/route/netconf.h b/include/netlink/route/netconf.h
new file mode 100644
index 00000000..19934381
--- /dev/null
+++ b/include/netlink/route/netconf.h
@@ -0,0 +1,44 @@
+/*
+ * netlink/route/netconf.h rtnetlink netconf layer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2017 David Ahern <dsa@cumulusnetworks.com>
+ */
+
+#ifndef NETCONF_H_
+#define NETCONF_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rtnl_netconf;
+
+int rtnl_netconf_alloc_cache(struct nl_sock *sk, struct nl_cache **result);
+
+struct rtnl_netconf *rtnl_netconf_get_by_idx(struct nl_cache *cache, int family,
+ int ifindex);
+struct rtnl_netconf *rtnl_netconf_get_all(struct nl_cache *cache,
+ int family);
+struct rtnl_netconf *rtnl_netconf_get_default(struct nl_cache *cache,
+ int family);
+void rtnl_netconf_put(struct rtnl_netconf *nc);
+
+int rtnl_netconf_get_family(struct rtnl_netconf *nc, int *val);
+int rtnl_netconf_get_ifindex(struct rtnl_netconf *nc, int *val);
+int rtnl_netconf_get_forwarding(struct rtnl_netconf *nc, int *val);
+int rtnl_netconf_get_mc_forwarding(struct rtnl_netconf *nc, int *val);
+int rtnl_netconf_get_rp_filter(struct rtnl_netconf *nc, int *val);
+int rtnl_netconf_get_proxy_neigh(struct rtnl_netconf *nc, int *val);
+int rtnl_netconf_get_ignore_routes_linkdown(struct rtnl_netconf *nc, int *val);
+int rtnl_netconf_get_input(struct rtnl_netconf *nc, int *val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/nexthop.h b/include/netlink/route/nexthop.h
index 2aa44dce..5b422ddf 100644
--- a/include/netlink/route/nexthop.h
+++ b/include/netlink/route/nexthop.h
@@ -55,9 +55,21 @@ extern void rtnl_route_nh_set_realms(struct rtnl_nexthop *,
uint32_t);
extern uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *);
+extern int rtnl_route_nh_set_newdst(struct rtnl_nexthop *,
+ struct nl_addr *);
+extern struct nl_addr * rtnl_route_nh_get_newdst(struct rtnl_nexthop *);
+extern int rtnl_route_nh_set_via(struct rtnl_nexthop *,
+ struct nl_addr *);
+extern struct nl_addr * rtnl_route_nh_get_via(struct rtnl_nexthop *);
extern char * rtnl_route_nh_flags2str(int, char *, size_t);
extern int rtnl_route_nh_str2flags(const char *);
+/*
+ * nexthop encapsulations
+ */
+extern int rtnl_route_nh_encap_mpls(struct rtnl_nexthop *nh,
+ struct nl_addr *addr,
+ uint8_t ttl);
#ifdef __cplusplus
}
#endif
diff --git a/include/netlink/route/qdisc/hfsc.h b/include/netlink/route/qdisc/hfsc.h
new file mode 100644
index 00000000..4c338099
--- /dev/null
+++ b/include/netlink/route/qdisc/hfsc.h
@@ -0,0 +1,39 @@
+/*
+ * netlink/route/sch/hfsc.h HFSC Qdisc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2014 Cong Wang <xiyou.wangcong@gmail.com>
+ */
+
+#ifndef NETLINK_HFSC_H_
+#define NETLINK_HFSC_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/tc.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct tc_service_curve;
+
+extern uint32_t rtnl_qdisc_hfsc_get_defcls(const struct rtnl_qdisc *);
+extern int rtnl_qdisc_hfsc_set_defcls(struct rtnl_qdisc *, uint32_t);
+
+extern int rtnl_class_hfsc_get_rsc(const struct rtnl_class *cls, struct tc_service_curve *tsc);
+extern int rtnl_class_hfsc_set_rsc(struct rtnl_class *cls, const struct tc_service_curve *tsc);
+extern int rtnl_class_hfsc_get_fsc(const struct rtnl_class *cls, struct tc_service_curve *tsc);
+extern int rtnl_class_hfsc_set_fsc(struct rtnl_class *cls, const struct tc_service_curve *tsc);
+extern int rtnl_class_hfsc_get_usc(const struct rtnl_class *cls, struct tc_service_curve *tsc);
+extern int rtnl_class_hfsc_set_usc(struct rtnl_class *cls, const struct tc_service_curve *tsc);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/route/qdisc/htb.h b/include/netlink/route/qdisc/htb.h
index c909f843..5d7ca452 100644
--- a/include/netlink/route/qdisc/htb.h
+++ b/include/netlink/route/qdisc/htb.h
@@ -30,16 +30,24 @@ extern int rtnl_htb_set_defcls(struct rtnl_qdisc *, uint32_t);
extern uint32_t rtnl_htb_get_prio(struct rtnl_class *);
extern int rtnl_htb_set_prio(struct rtnl_class *, uint32_t);
-extern uint32_t rtnl_htb_get_rate(struct rtnl_class *);
-extern int rtnl_htb_set_rate(struct rtnl_class *, uint32_t);
-extern uint32_t rtnl_htb_get_ceil(struct rtnl_class *);
-extern int rtnl_htb_set_ceil(struct rtnl_class *, uint32_t);
+
+extern uint32_t rtnl_htb_get_rate(struct rtnl_class *);
+extern int rtnl_htb_set_rate(struct rtnl_class *, uint32_t);
+extern uint32_t rtnl_htb_get_ceil(struct rtnl_class *);
+extern int rtnl_htb_set_ceil(struct rtnl_class *, uint32_t);
+
+extern int rtnl_htb_get_rate64(struct rtnl_class *, uint64_t *);
+extern int rtnl_htb_set_rate64(struct rtnl_class *, uint64_t);
+extern int rtnl_htb_get_ceil64(struct rtnl_class *, uint64_t *);
+extern int rtnl_htb_set_ceil64(struct rtnl_class *, uint64_t);
+
extern uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *);
extern int rtnl_htb_set_rbuffer(struct rtnl_class *, uint32_t);
extern uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *);
extern int rtnl_htb_set_cbuffer(struct rtnl_class *, uint32_t);
extern uint32_t rtnl_htb_get_quantum(struct rtnl_class *);
extern int rtnl_htb_set_quantum(struct rtnl_class *, uint32_t);
+extern int rtnl_htb_set_level(struct rtnl_class *, int);
extern int rtnl_htb_get_level(struct rtnl_class *);
#ifdef __cplusplus
diff --git a/include/netlink/route/qdisc/mqprio.h b/include/netlink/route/qdisc/mqprio.h
new file mode 100644
index 00000000..1a38aeb2
--- /dev/null
+++ b/include/netlink/route/qdisc/mqprio.h
@@ -0,0 +1,48 @@
+/*
+ * lib/route/qdisc/mqprio.c MQPRIO Qdisc/Class
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@westermo.se>
+ */
+
+#ifndef NETLINK_MQPRIO_H_
+#define NETLINK_MQPRIO_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/qdisc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_qdisc_mqprio_set_num_tc(struct rtnl_qdisc *qdisc, int num_tc);
+extern int rtnl_qdisc_mqprio_get_num_tc(struct rtnl_qdisc *qdisc);
+extern int rtnl_qdisc_mqprio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
+ int len);
+extern uint8_t *rtnl_qdisc_mqprio_get_priomap(struct rtnl_qdisc *qdisc);
+extern int rtnl_qdisc_mqprio_hw_offload(struct rtnl_qdisc *qdisc, int offload);
+extern int rtnl_qdisc_mqprio_get_hw_offload(struct rtnl_qdisc *qdisc);
+extern int rtnl_qdisc_mqprio_set_queue(struct rtnl_qdisc *qdisc, uint16_t count[],
+ uint16_t offset[], int len);
+extern int rtnl_qdisc_mqprio_get_queue(struct rtnl_qdisc *qdisc, uint16_t *count,
+ uint16_t *offset);
+extern int rtnl_qdisc_mqprio_set_mode(struct rtnl_qdisc *qdisc, uint16_t mode);
+extern int rtnl_qdisc_mqprio_get_mode(struct rtnl_qdisc *qdisc);
+extern int rtnl_qdisc_mqprio_set_shaper(struct rtnl_qdisc *qdisc, uint16_t shaper);
+extern int rtnl_qdisc_mqprio_get_shaper(struct rtnl_qdisc *qdisc);
+extern int rtnl_qdisc_mqprio_set_min_rate(struct rtnl_qdisc *qdisc, uint64_t min[],
+ int len);
+extern int rtnl_qdisc_mqprio_get_min_rate(struct rtnl_qdisc *qdisc, uint64_t *min);
+extern int rtnl_qdisc_mqprio_set_max_rate(struct rtnl_qdisc *qdisc, uint64_t max[],
+ int len);
+extern int rtnl_qdisc_mqprio_get_max_rate(struct rtnl_qdisc *qdisc, uint64_t *max);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETLINK_MQPRIO_H_ */
diff --git a/include/netlink/route/qdisc/netem.h b/include/netlink/route/qdisc/netem.h
index 4b071bf1..47c9dd83 100644
--- a/include/netlink/route/qdisc/netem.h
+++ b/include/netlink/route/qdisc/netem.h
@@ -66,6 +66,7 @@ extern int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *);
/* Delay Distribution */
#define MAXDIST 65536
extern int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *, const char *);
+extern int rtnl_netem_set_delay_distribution_data(struct rtnl_qdisc *, const int16_t *, size_t len);
extern int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *);
extern int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *, int16_t **);
diff --git a/include/netlink/route/qdisc/red.h b/include/netlink/route/qdisc/red.h
index a4e8642f..accb8d94 100644
--- a/include/netlink/route/qdisc/red.h
+++ b/include/netlink/route/qdisc/red.h
@@ -14,4 +14,7 @@
#include <netlink/netlink.h>
+extern void rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit);
+extern int rtnl_red_get_limit(struct rtnl_qdisc *qdisc);
+
#endif
diff --git a/include/netlink/route/route.h b/include/netlink/route/route.h
index 477250dd..824dae35 100644
--- a/include/netlink/route/route.h
+++ b/include/netlink/route/route.h
@@ -94,6 +94,9 @@ extern struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *);
extern void rtnl_route_set_iif(struct rtnl_route *, int);
extern int rtnl_route_get_iif(struct rtnl_route *);
extern int rtnl_route_get_src_len(struct rtnl_route *);
+extern void rtnl_route_set_ttl_propagate(struct rtnl_route *route,
+ uint8_t ttl_prop);
+extern int rtnl_route_get_ttl_propagate(struct rtnl_route *route);
extern void rtnl_route_add_nexthop(struct rtnl_route *,
struct rtnl_nexthop *);
diff --git a/include/netlink/route/rule.h b/include/netlink/route/rule.h
index 760b782a..d0c335fc 100644
--- a/include/netlink/route/rule.h
+++ b/include/netlink/route/rule.h
@@ -67,6 +67,24 @@ extern void rtnl_rule_set_realms(struct rtnl_rule *, uint32_t);
extern uint32_t rtnl_rule_get_realms(struct rtnl_rule *);
extern void rtnl_rule_set_goto(struct rtnl_rule *, uint32_t);
extern uint32_t rtnl_rule_get_goto(struct rtnl_rule *);
+extern void rtnl_rule_set_l3mdev(struct rtnl_rule *, int);
+extern int rtnl_rule_get_l3mdev(struct rtnl_rule *);
+extern int rtnl_rule_set_protocol(struct rtnl_rule *, uint8_t);
+extern int rtnl_rule_get_protocol(struct rtnl_rule *, uint8_t *);
+extern int rtnl_rule_set_ipproto(struct rtnl_rule *, uint8_t);
+extern int rtnl_rule_get_ipproto(struct rtnl_rule *, uint8_t *);
+extern int rtnl_rule_set_sport(struct rtnl_rule *, uint16_t start);
+extern int rtnl_rule_set_sport_range(struct rtnl_rule *,
+ uint16_t start,
+ uint16_t end);
+extern int rtnl_rule_get_sport(struct rtnl_rule *, uint16_t *start,
+ uint16_t *end);
+extern int rtnl_rule_set_dport(struct rtnl_rule *, uint16_t start);
+extern int rtnl_rule_set_dport_range(struct rtnl_rule *,
+ uint16_t start,
+ uint16_t end);
+extern int rtnl_rule_get_dport(struct rtnl_rule *, uint16_t *start,
+ uint16_t *end);
#ifdef __cplusplus
}
diff --git a/include/netlink/route/tc.h b/include/netlink/route/tc.h
index 870c1f26..51d670ae 100644
--- a/include/netlink/route/tc.h
+++ b/include/netlink/route/tc.h
@@ -97,6 +97,8 @@ extern uint32_t rtnl_tc_get_parent(struct rtnl_tc *);
extern int rtnl_tc_set_kind(struct rtnl_tc *, const char *);
extern char * rtnl_tc_get_kind(struct rtnl_tc *);
extern uint64_t rtnl_tc_get_stat(struct rtnl_tc *, enum rtnl_tc_stat);
+extern char * rtnl_tc_stat2str(enum rtnl_tc_stat, char *, size_t);
+extern int rtnl_tc_str2stat(const char *);
extern int rtnl_tc_calc_txtime(int, int);
extern int rtnl_tc_calc_bufsize(int, int);
@@ -107,6 +109,8 @@ extern char * rtnl_tc_handle2str(uint32_t, char *, size_t);
extern int rtnl_tc_str2handle(const char *, uint32_t *);
extern int rtnl_classid_generate(const char *, uint32_t *,
uint32_t);
+extern void rtnl_tc_set_chain(struct rtnl_tc *, uint32_t);
+extern int rtnl_tc_get_chain(struct rtnl_tc *, uint32_t *);
#ifdef __cplusplus
}
diff --git a/include/netlink/socket.h b/include/netlink/socket.h
index 1007eba0..9a68cad9 100644
--- a/include/netlink/socket.h
+++ b/include/netlink/socket.h
@@ -60,6 +60,7 @@ extern void nl_socket_disable_auto_ack(struct nl_sock *);
extern void nl_socket_enable_auto_ack(struct nl_sock *);
extern int nl_socket_get_fd(const struct nl_sock *);
+extern int nl_socket_set_fd(struct nl_sock *sk, int protocol, int fd);
extern int nl_socket_set_nonblocking(const struct nl_sock *);
extern void nl_socket_enable_msg_peek(struct nl_sock *);
extern void nl_socket_disable_msg_peek(struct nl_sock *);
diff --git a/include/netlink/utils.h b/include/netlink/utils.h
index 6b4b7874..b05ce661 100644
--- a/include/netlink/utils.h
+++ b/include/netlink/utils.h
@@ -113,8 +113,202 @@ enum {
NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE = 4,
#define NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE
- __NL_CAPABILITY_MAX
-#define NL_CAPABILITY_MAX (__NL_CAPABILITY_MAX - 1)
+ /**
+ * Indicate that rtnl_link_get_kernel() fails with -NLE_OPNOTSUPP in case
+ * of older kernals not supporting lookup by ifname. This changes behavior
+ * from returning -NLE_INVAL to return -NLE_OPNOTSUPP.
+ */
+ NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_FAIL_OPNOTSUPP = 5,
+#define NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_FAIL_OPNOTSUPP NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_FAIL_OPNOTSUPP
+
+ /**
+ * Also consider the a_cacheinfo field (ADDR_ATTR_CACHEINFO) that contains the
+ * address timestamps and expiry when comparing struct rtnl_addr objects with
+ * nl_object_diff().
+ */
+ NL_CAPABILITY_ROUTE_ADDR_COMPARE_CACHEINFO = 6,
+#define NL_CAPABILITY_ROUTE_ADDR_COMPARE_CACHEINFO NL_CAPABILITY_ROUTE_ADDR_COMPARE_CACHEINFO
+
+ /**
+ * The library version is libnl3 3.2.26 or newer. This capability should never be backported.
+ */
+ NL_CAPABILITY_VERSION_3_2_26 = 7,
+#define NL_CAPABILITY_VERSION_3_2_26 NL_CAPABILITY_VERSION_3_2_26
+
+ /**
+ * nl_recv() fails with NLE_MSG_TRUNC if a message got truncated
+ * with NL_MSG_PEEK disabled. Previously, the failed message was wrongly
+ * discarded and the next message received.
+ */
+ NL_CAPABILITY_NL_RECV_FAIL_TRUNC_NO_PEEK = 8,
+#define NL_CAPABILITY_NL_RECV_FAIL_TRUNC_NO_PEEK NL_CAPABILITY_NL_RECV_FAIL_TRUNC_NO_PEEK
+
+ /**
+ * rtnl_link_build_change_request() and rtnl_link_change() would set ifi.ifi_flags but leave
+ * ifi.ifi_change at zero. This was later fixed to set ifi.ifi_change to the flags that are actually
+ * set in changes.
+ */
+ NL_CAPABILITY_LINK_BUILD_CHANGE_REQUEST_SET_CHANGE = 9,
+#define NL_CAPABILITY_LINK_BUILD_CHANGE_REQUEST_SET_CHANGE NL_CAPABILITY_LINK_BUILD_CHANGE_REQUEST_SET_CHANGE
+
+ /**
+ * Between 3.2.14 (64fcb47a36ec12d7e7f00605f6a8952ce985dd08) and 3.2.22 (8571f58f23763d8db7365d02c9b27832ad3d7005),
+ * rtnl_neigh_get() behaved differently and only returned objects with family AF_UNSPEC.
+ * This capability indicates, that the function was fixed. The absense of the capability,
+ * doesn't indicate however which behavior the function will have. So beware. */
+ NL_CAPABILITY_RTNL_NEIGH_GET_FILTER_AF_UNSPEC_FIX = 10,
+#define NL_CAPABILITY_RTNL_NEIGH_GET_FILTER_AF_UNSPEC_FIX NL_CAPABILITY_RTNL_NEIGH_GET_FILTER_AF_UNSPEC_FIX
+
+ /**
+ * The library version is libnl3 3.2.27 or newer. This capability should never be backported.
+ */
+ NL_CAPABILITY_VERSION_3_2_27 = 11,
+#define NL_CAPABILITY_VERSION_3_2_27 NL_CAPABILITY_VERSION_3_2_27
+
+ /**
+ * Properly serialize vlan protocol IFLA_VLAN_PROTOCOL.
+ */
+ NL_CAPABILITY_RTNL_LINK_VLAN_PROTOCOL_SERIALZE = 12,
+#define NL_CAPABILITY_RTNL_LINK_VLAN_PROTOCOL_SERIALZE NL_CAPABILITY_RTNL_LINK_VLAN_PROTOCOL_SERIALZE
+
+ /**
+ * Properly read gre REMOTE port.
+ */
+ NL_CAPABILITY_RTNL_LINK_PARSE_GRE_REMOTE = 13,
+#define NL_CAPABILITY_RTNL_LINK_PARSE_GRE_REMOTE NL_CAPABILITY_RTNL_LINK_PARSE_GRE_REMOTE
+
+ /**
+ * Don't skip over vlan ingress-map entries with "to" field zero when serializing
+ * a netlink message. Previously such entires would be ignored which inhibits the
+ * user from clearing ingress map entries.
+ */
+ NL_CAPABILITY_RTNL_LINK_VLAN_INGRESS_MAP_CLEAR = 14,
+#define NL_CAPABILITY_RTNL_LINK_VLAN_INGRESS_MAP_CLEAR NL_CAPABILITY_RTNL_LINK_VLAN_INGRESS_MAP_CLEAR
+
+ /**
+ * Consider vxlan link info for nl_object_diff().
+ */
+ NL_CAPABILITY_RTNL_LINK_VXLAN_IO_COMPARE = 15,
+#define NL_CAPABILITY_RTNL_LINK_VXLAN_IO_COMPARE NL_CAPABILITY_RTNL_LINK_VXLAN_IO_COMPARE
+
+ /**
+ * Support 64 bit attributes for nl_object_diff().
+ */
+ NL_CAPABILITY_NL_OBJECT_DIFF64 = 16,
+#define NL_CAPABILITY_NL_OBJECT_DIFF64 NL_CAPABILITY_NL_OBJECT_DIFF64
+
+ /**
+ * Support omitting @key argument to xfrmnl_sa_get_*_params() to check
+ * for required buffer size for key.
+ */
+ NL_CAPABILITY_XFRM_SA_KEY_SIZE = 17,
+#define NL_CAPABILITY_XFRM_SA_KEY_SIZE NL_CAPABILITY_XFRM_SA_KEY_SIZE
+
+ /**
+ * Properly handle nl_object_identity() for AF_INET and AF_INET6 addresses
+ * and properly handle the peer/IFA_ADDRESS for IPv4 addresses.
+ */
+ NL_CAPABILITY_RTNL_ADDR_PEER_FIX = 18,
+#define NL_CAPABILITY_RTNL_ADDR_PEER_FIX NL_CAPABILITY_RTNL_ADDR_PEER_FIX
+
+ /**
+ * The library version is libnl3 3.2.28 or newer. This capability should never be backported.
+ */
+ NL_CAPABILITY_VERSION_3_2_28 = 19,
+#define NL_CAPABILITY_VERSION_3_2_28 NL_CAPABILITY_VERSION_3_2_28
+
+ /**
+ * After NL_CAPABILITY_RTNL_ADDR_PEER_FIX, a follow up regression to lookup
+ * IPv4 addresses in the cache was fixed (PR#105).
+ */
+ NL_CAPABILITY_RTNL_ADDR_PEER_ID_FIX = 20,
+#define NL_CAPABILITY_RTNL_ADDR_PEER_ID_FIX NL_CAPABILITY_RTNL_ADDR_PEER_ID_FIX
+
+ /**
+ * nl_addr_fill_sockaddr() properly checks that the provided address to
+ * avoid read-out-of-bounds for invalid addresses.
+ */
+ NL_CAPABILITY_NL_ADDR_FILL_SOCKADDR = 21,
+#define NL_CAPABILITY_NL_ADDR_FILL_SOCKADDR NL_CAPABILITY_NL_ADDR_FILL_SOCKADDR
+
+ /**
+ * Support omitting @ctx_str argument to xfrmnl_sa_get_sec_ctx() to check
+ * for required buffer size for context string.
+ */
+ NL_CAPABILITY_XFRM_SEC_CTX_LEN = 22,
+#define NL_CAPABILITY_XFRM_SEC_CTX_LEN NL_CAPABILITY_XFRM_SEC_CTX_LEN
+
+ /**
+ * rtnl_link_build_add_request() would set ifi.ifi_flags but leave ifi.ifi_change at zero.
+ * This was later fixed to set ifi.ifi_change to the flags that are actually
+ * set
+ */
+ NL_CAPABILITY_LINK_BUILD_ADD_REQUEST_SET_CHANGE = 23,
+#define NL_CAPABILITY_LINK_BUILD_ADD_REQUEST_SET_CHANGE NL_CAPABILITY_LINK_BUILD_ADD_REQUEST_SET_CHANGE
+
+ /* Older versions of libnl3 would not use MSG_PEEK for nl_recvmsgs() unless calling
+ * nl_socket_enable_msg_peek(). Instead, the user had to specify the buffer size via
+ * nl_socket_set_msg_buf_size(), which in turn would default to 4*getpagesize().
+ *
+ * The default value might not be large enough, so users who were not aware of the
+ * problem easily ended up using a too small receive buffer. Usually, one wants to
+ * avoid MSG_PEEK for recvmsg() because it requires an additional syscall.
+ *
+ * Now, as indicated by this capability, nl_recvmsgs() would use MSG_PEEK by default. The
+ * user still can explicitly disable MSG_PEEK by calling nl_socket_disable_msg_peek() or
+ * by setting the nl_socket_set_msg_buf_size() to a non-zero value.
+ */
+ NL_CAPABILITY_NL_RECVMSGS_PEEK_BY_DEFAULT = 24,
+#define NL_CAPABILITY_NL_RECVMSGS_PEEK_BY_DEFAULT NL_CAPABILITY_NL_RECVMSGS_PEEK_BY_DEFAULT
+
+ /**
+ * The library version is libnl3 3.2.29 or newer. This capability should never be backported.
+ */
+ NL_CAPABILITY_VERSION_3_2_29 = 25,
+#define NL_CAPABILITY_VERSION_3_2_29 NL_CAPABILITY_VERSION_3_2_29
+
+ /**
+ * Support omitting @ctx_str argument to xfrmnl_sp_get_sec_ctx() to check
+ * for required buffer size for context string.
+ */
+ NL_CAPABILITY_XFRM_SP_SEC_CTX_LEN = 26,
+#define NL_CAPABILITY_XFRM_SP_SEC_CTX_LEN NL_CAPABILITY_XFRM_SP_SEC_CTX_LEN
+
+ /**
+ * The library version is libnl3 3.3.0 or newer. This capability should never be backported.
+ */
+ NL_CAPABILITY_VERSION_3_3_0 = 27,
+#define NL_CAPABILITY_VERSION_3_3_0 NL_CAPABILITY_VERSION_3_3_0
+
+ /**
+ * The library version is libnl3 3.4.0 or newer. This capability should never be backported.
+ */
+ NL_CAPABILITY_VERSION_3_4_0 = 28,
+#define NL_CAPABILITY_VERSION_3_4_0 NL_CAPABILITY_VERSION_3_4_0
+
+ /**
+ * Fixed memory corruption in rtnl_link_vlan_set_egress_map(). Previously, if you tried
+ * to add more then 4 mappings, a buffer overflow occured. Also fixed nl_object_clone()
+ * for VLAN links.
+ */
+ NL_CAPABILITY_ROUTE_FIX_VLAN_SET_EGRESS_MAP = 29,
+#define NL_CAPABILITY_ROUTE_FIX_VLAN_SET_EGRESS_MAP NL_CAPABILITY_ROUTE_FIX_VLAN_SET_EGRESS_MAP
+
+ /**
+ * The library version is libnl3 3.5.0 or newer. This capability should never be backported.
+ */
+ NL_CAPABILITY_VERSION_3_5_0 = 30,
+#define NL_CAPABILITY_VERSION_3_5_0 NL_CAPABILITY_VERSION_3_5_0
+
+ __NL_CAPABILITY_MAX,
+ NL_CAPABILITY_MAX = (__NL_CAPABILITY_MAX - 1),
+#define NL_CAPABILITY_MAX NL_CAPABILITY_MAX
+
+ /**
+ * The range 0x7000 to 0x7FFF is reserved for private capabilities. Upstream libnl3 will
+ * not register capabilities in this range. However, instead of adding private capabilities,
+ * better register their number with upstream libnl3. */
+#define NL_CAPABILITY_IS_USER_RESERVED(cap) ( ((cap) & ~0x0FFF) == 0x7000 )
};
int nl_has_capability (int capability);
diff --git a/include/netlink/version.h b/include/netlink/version.h
index a8094420..093fd913 100644
--- a/include/netlink/version.h
+++ b/include/netlink/version.h
@@ -14,18 +14,18 @@
/* Compile Time Versioning Information */
-#define LIBNL_STRING "libnl 3.2.25"
-#define LIBNL_VERSION "3.2.25"
+#define LIBNL_STRING "libnl 3.5.0"
+#define LIBNL_VERSION "3.5.0"
#define LIBNL_VER_MAJ 3
-#define LIBNL_VER_MIN 2
-#define LIBNL_VER_MIC 25
+#define LIBNL_VER_MIN 5
+#define LIBNL_VER_MIC 0
#define LIBNL_VER(maj,min) ((maj) << 8 | (min))
#define LIBNL_VER_NUM LIBNL_VER(LIBNL_VER_MAJ, LIBNL_VER_MIN)
-#define LIBNL_CURRENT 220
+#define LIBNL_CURRENT 226
#define LIBNL_REVISION 0
-#define LIBNL_AGE 20
+#define LIBNL_AGE 26
/* Run-time version information */
diff --git a/include/netlink/xfrm/ae.h b/include/netlink/xfrm/ae.h
new file mode 100644
index 00000000..95112dd5
--- /dev/null
+++ b/include/netlink/xfrm/ae.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+#ifndef NETLINK_XFRM_AE_H_
+#define NETLINK_XFRM_AE_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <linux/xfrm.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xfrmnl_ae;
+
+extern struct xfrmnl_ae*xfrmnl_ae_alloc(void);
+extern void xfrmnl_ae_put(struct xfrmnl_ae *);
+
+extern int xfrmnl_ae_get_kernel(struct nl_sock*, struct nl_addr*, unsigned int, unsigned int,
+ unsigned int, unsigned int, struct xfrmnl_ae**);
+extern int xfrmnl_ae_set(struct nl_sock*, struct xfrmnl_ae*, int);
+
+extern int xfrmnl_ae_parse(struct nlmsghdr*, struct xfrmnl_ae **);
+extern int xfrmnl_ae_build_get_request(struct nl_addr*, unsigned int, unsigned int,
+ unsigned int, unsigned int, struct nl_msg **);
+
+extern struct nl_addr* xfrmnl_ae_get_daddr (struct xfrmnl_ae*);
+extern int xfrmnl_ae_set_daddr (struct xfrmnl_ae*, struct nl_addr*);
+
+extern int xfrmnl_ae_get_spi (struct xfrmnl_ae*);
+extern int xfrmnl_ae_set_spi (struct xfrmnl_ae*, unsigned int);
+
+extern int xfrmnl_ae_get_family (struct xfrmnl_ae*);
+extern int xfrmnl_ae_set_family (struct xfrmnl_ae*, unsigned int);
+
+extern int xfrmnl_ae_get_proto (struct xfrmnl_ae*);
+extern int xfrmnl_ae_set_proto (struct xfrmnl_ae*, unsigned int);
+
+extern struct nl_addr* xfrmnl_ae_get_saddr (struct xfrmnl_ae*);
+extern int xfrmnl_ae_set_saddr (struct xfrmnl_ae*, struct nl_addr*);
+
+extern int xfrmnl_ae_get_flags (struct xfrmnl_ae*);
+extern int xfrmnl_ae_set_flags (struct xfrmnl_ae*, unsigned int);
+
+extern int xfrmnl_ae_get_reqid (struct xfrmnl_ae*);
+extern int xfrmnl_ae_set_reqid (struct xfrmnl_ae*, unsigned int);
+
+extern int xfrmnl_ae_get_mark (struct xfrmnl_ae*, unsigned int*, unsigned int*);
+extern int xfrmnl_ae_set_mark (struct xfrmnl_ae*, unsigned int, unsigned int);
+
+extern int xfrmnl_ae_get_curlifetime (struct xfrmnl_ae*, unsigned long long int*,
+ unsigned long long int*, unsigned long long int*,
+ unsigned long long int*);
+extern int xfrmnl_ae_set_curlifetime (struct xfrmnl_ae*, unsigned long long int,
+ unsigned long long int, unsigned long long int,
+ unsigned long long int);
+
+extern int xfrmnl_ae_get_replay_maxage (struct xfrmnl_ae*);
+extern int xfrmnl_ae_set_replay_maxage (struct xfrmnl_ae*, unsigned int);
+
+extern int xfrmnl_ae_get_replay_maxdiff (struct xfrmnl_ae*);
+extern int xfrmnl_ae_set_replay_maxdiff (struct xfrmnl_ae*, unsigned int);
+
+extern int xfrmnl_ae_get_replay_state (struct xfrmnl_ae*, unsigned int*, unsigned int*, unsigned int*);
+extern int xfrmnl_ae_set_replay_state (struct xfrmnl_ae*, unsigned int, unsigned int, unsigned int);
+
+extern int xfrmnl_ae_get_replay_state_esn (struct xfrmnl_ae*, unsigned int*, unsigned int*, unsigned int*,
+ unsigned int*, unsigned int*, unsigned int*, unsigned int*);
+extern int xfrmnl_ae_set_replay_state_esn (struct xfrmnl_ae*, unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int, unsigned int, unsigned int*);
+
+extern char* xfrmnl_ae_flags2str(int, char *, size_t);
+extern int xfrmnl_ae_str2flag(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/xfrm/lifetime.h b/include/netlink/xfrm/lifetime.h
new file mode 100644
index 00000000..a5d5955d
--- /dev/null
+++ b/include/netlink/xfrm/lifetime.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+#ifndef NETLINK_XFRM_LTIME_H_
+#define NETLINK_XFRM_LTIME_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <linux/xfrm.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xfrmnl_ltime_cfg;
+
+/* Creation */
+extern struct xfrmnl_ltime_cfg* xfrmnl_ltime_cfg_alloc(void);
+extern struct xfrmnl_ltime_cfg* xfrmnl_ltime_cfg_clone(struct xfrmnl_ltime_cfg*);
+
+/* Usage Management */
+extern struct xfrmnl_ltime_cfg* xfrmnl_ltime_cfg_get(struct xfrmnl_ltime_cfg*);
+extern void xfrmnl_ltime_cfg_put(struct xfrmnl_ltime_cfg*);
+extern int xfrmnl_ltime_cfg_shared(struct xfrmnl_ltime_cfg*);
+extern int xfrmnl_ltime_cfg_cmp(struct xfrmnl_ltime_cfg*, struct xfrmnl_ltime_cfg*);
+
+/* Access Functions */
+extern unsigned long long xfrmnl_ltime_cfg_get_soft_bytelimit (struct xfrmnl_ltime_cfg*);
+extern int xfrmnl_ltime_cfg_set_soft_bytelimit (struct xfrmnl_ltime_cfg*, unsigned long long);
+
+extern unsigned long long xfrmnl_ltime_cfg_get_hard_bytelimit (struct xfrmnl_ltime_cfg*);
+extern int xfrmnl_ltime_cfg_set_hard_bytelimit (struct xfrmnl_ltime_cfg*, unsigned long long);
+
+extern unsigned long long xfrmnl_ltime_cfg_get_soft_packetlimit (struct xfrmnl_ltime_cfg*);
+extern int xfrmnl_ltime_cfg_set_soft_packetlimit (struct xfrmnl_ltime_cfg*, unsigned long long);
+
+extern unsigned long long xfrmnl_ltime_cfg_get_hard_packetlimit (struct xfrmnl_ltime_cfg*);
+extern int xfrmnl_ltime_cfg_set_hard_packetlimit (struct xfrmnl_ltime_cfg*, unsigned long long);
+
+extern unsigned long long xfrmnl_ltime_cfg_get_soft_addexpires (struct xfrmnl_ltime_cfg*);
+extern int xfrmnl_ltime_cfg_set_soft_addexpires (struct xfrmnl_ltime_cfg*, unsigned long long);
+
+extern unsigned long long xfrmnl_ltime_cfg_get_hard_addexpires (struct xfrmnl_ltime_cfg*);
+extern int xfrmnl_ltime_cfg_set_hard_addexpires (struct xfrmnl_ltime_cfg*, unsigned long long);
+
+extern unsigned long long xfrmnl_ltime_cfg_get_soft_useexpires (struct xfrmnl_ltime_cfg*);
+extern int xfrmnl_ltime_cfg_set_soft_useexpires (struct xfrmnl_ltime_cfg*, unsigned long long);
+
+extern unsigned long long xfrmnl_ltime_cfg_get_hard_useexpires (struct xfrmnl_ltime_cfg*);
+extern int xfrmnl_ltime_cfg_set_hard_useexpires (struct xfrmnl_ltime_cfg*, unsigned long long);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/xfrm/sa.h b/include/netlink/xfrm/sa.h
new file mode 100644
index 00000000..7362c361
--- /dev/null
+++ b/include/netlink/xfrm/sa.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+#ifndef NETLINK_XFRM_SA_H_
+#define NETLINK_XFRM_SA_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <linux/xfrm.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xfrmnl_sa;
+
+extern struct xfrmnl_sa* xfrmnl_sa_alloc(void);
+extern void xfrmnl_sa_put(struct xfrmnl_sa *);
+
+extern int xfrmnl_sa_alloc_cache(struct nl_sock *, struct nl_cache **);
+extern struct xfrmnl_sa* xfrmnl_sa_get(struct nl_cache*, struct nl_addr*, unsigned int, unsigned int);
+
+extern int xfrmnl_sa_parse(struct nlmsghdr *n, struct xfrmnl_sa **result);
+
+extern int xfrmnl_sa_build_get_request(struct nl_addr*, unsigned int, unsigned int,
+ unsigned int, unsigned int, struct nl_msg **);
+extern int xfrmnl_sa_get_kernel(struct nl_sock*, struct nl_addr*, unsigned int,
+ unsigned int, unsigned int, unsigned int, struct xfrmnl_sa**);
+
+extern int xfrmnl_sa_build_add_request(struct xfrmnl_sa*, int, struct nl_msg **);
+extern int xfrmnl_sa_add(struct nl_sock*, struct xfrmnl_sa*, int);
+
+extern int xfrmnl_sa_build_update_request(struct xfrmnl_sa*, int, struct nl_msg **);
+extern int xfrmnl_sa_update(struct nl_sock*, struct xfrmnl_sa*, int);
+
+extern int xfrmnl_sa_build_delete_request(struct xfrmnl_sa*, int, struct nl_msg **);
+extern int xfrmnl_sa_delete(struct nl_sock*, struct xfrmnl_sa*, int);
+
+extern struct xfrmnl_sel* xfrmnl_sa_get_sel (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_sel (struct xfrmnl_sa*, struct xfrmnl_sel*);
+
+extern struct nl_addr* xfrmnl_sa_get_daddr (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_daddr (struct xfrmnl_sa*, struct nl_addr*);
+
+extern int xfrmnl_sa_get_spi (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_spi (struct xfrmnl_sa*, unsigned int);
+
+extern int xfrmnl_sa_get_proto (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_proto (struct xfrmnl_sa*, unsigned int);
+
+extern struct nl_addr* xfrmnl_sa_get_saddr (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_saddr (struct xfrmnl_sa*, struct nl_addr*);
+
+extern struct xfrmnl_ltime_cfg* xfrmnl_sa_get_lifetime_cfg (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_lifetime_cfg (struct xfrmnl_sa*, struct xfrmnl_ltime_cfg*);
+
+extern int xfrmnl_sa_get_curlifetime (struct xfrmnl_sa*, unsigned long long int*,
+ unsigned long long int*, unsigned long long int*,
+ unsigned long long int*);
+
+extern int xfrmnl_sa_get_stats (struct xfrmnl_sa*, unsigned long long int*,
+ unsigned long long int*, unsigned long long int*);
+
+extern int xfrmnl_sa_get_seq (struct xfrmnl_sa*);
+
+extern int xfrmnl_sa_get_reqid (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_reqid (struct xfrmnl_sa*, unsigned int);
+
+extern int xfrmnl_sa_get_family (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_family (struct xfrmnl_sa*, unsigned int);
+
+extern int xfrmnl_sa_get_mode (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_mode (struct xfrmnl_sa*, unsigned int);
+
+extern int xfrmnl_sa_get_replay_window (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_replay_window (struct xfrmnl_sa*, unsigned int);
+
+extern int xfrmnl_sa_get_flags (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_flags (struct xfrmnl_sa*, unsigned int);
+
+extern int xfrmnl_sa_get_aead_params (struct xfrmnl_sa*, char*, unsigned int*,
+ unsigned int*, char*);
+extern int xfrmnl_sa_set_aead_params (struct xfrmnl_sa*, const char*, unsigned int,
+ unsigned int, const char*);
+
+extern int xfrmnl_sa_get_auth_params (struct xfrmnl_sa*, char*, unsigned int*,
+ unsigned int*, char*);
+extern int xfrmnl_sa_set_auth_params (struct xfrmnl_sa*, const char*, unsigned int,
+ unsigned int, const char*);
+
+extern int xfrmnl_sa_get_crypto_params (struct xfrmnl_sa*, char*, unsigned int*, char*);
+extern int xfrmnl_sa_set_crypto_params (struct xfrmnl_sa*, const char*, unsigned int,
+ const char*);
+
+extern int xfrmnl_sa_get_comp_params (struct xfrmnl_sa*, char*, unsigned int*, char*);
+extern int xfrmnl_sa_set_comp_params (struct xfrmnl_sa*, const char*, unsigned int,
+ const char*);
+
+extern int xfrmnl_sa_get_encap_tmpl (struct xfrmnl_sa*, unsigned int*, unsigned int*,
+ unsigned int*, struct nl_addr**);
+extern int xfrmnl_sa_set_encap_tmpl (struct xfrmnl_sa*, unsigned int, unsigned int,
+ unsigned int, struct nl_addr*);
+
+extern int xfrmnl_sa_get_tfcpad (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_tfcpad (struct xfrmnl_sa*, unsigned int);
+
+extern struct nl_addr* xfrmnl_sa_get_coaddr (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_coaddr (struct xfrmnl_sa*, struct nl_addr*);
+
+extern int xfrmnl_sa_get_mark (struct xfrmnl_sa*, unsigned int*, unsigned int*);
+extern int xfrmnl_sa_set_mark (struct xfrmnl_sa*, unsigned int, unsigned int);
+
+extern int xfrmnl_sa_get_sec_ctx (struct xfrmnl_sa*, unsigned int*, unsigned int*,
+ unsigned int*, unsigned int*, char*);
+extern int xfrmnl_sa_set_sec_ctx (struct xfrmnl_sa*, unsigned int, unsigned int,
+ unsigned int, unsigned int, const char*);
+
+extern int xfrmnl_sa_get_replay_maxage (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_replay_maxage (struct xfrmnl_sa*, unsigned int);
+
+extern int xfrmnl_sa_get_replay_maxdiff (struct xfrmnl_sa*);
+extern int xfrmnl_sa_set_replay_maxdiff (struct xfrmnl_sa*, unsigned int);
+
+extern int xfrmnl_sa_get_replay_state (struct xfrmnl_sa*, unsigned int*,
+ unsigned int*, unsigned int*);
+extern int xfrmnl_sa_set_replay_state (struct xfrmnl_sa*, unsigned int,
+ unsigned int, unsigned int);
+
+extern int xfrmnl_sa_get_replay_state_esn (struct xfrmnl_sa*, unsigned int*, unsigned int*,
+ unsigned int*, unsigned int*, unsigned int*,
+ unsigned int*, unsigned int*);
+extern int xfrmnl_sa_set_replay_state_esn (struct xfrmnl_sa*, unsigned int, unsigned int,
+ unsigned int, unsigned int, unsigned int,
+ unsigned int, unsigned int*);
+
+extern int xfrmnl_sa_is_expiry_reached (struct xfrmnl_sa*);
+extern int xfrmnl_sa_is_hardexpiry_reached (struct xfrmnl_sa*);
+
+extern char* xfrmnl_sa_flags2str(int, char *, size_t);
+extern int xfrmnl_sa_str2flag(const char *);
+
+extern char* xfrmnl_sa_mode2str(int, char *, size_t);
+extern int xfrmnl_sa_str2mode(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/xfrm/selector.h b/include/netlink/xfrm/selector.h
new file mode 100644
index 00000000..2ee6842a
--- /dev/null
+++ b/include/netlink/xfrm/selector.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+#ifndef NETLINK_XFRM_SEL_H_
+#define NETLINK_XFRM_SEL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <linux/xfrm.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xfrmnl_sel;
+
+/* Creation */
+extern struct xfrmnl_sel* xfrmnl_sel_alloc(void);
+extern struct xfrmnl_sel* xfrmnl_sel_clone(struct xfrmnl_sel*);
+
+/* Usage Management */
+extern struct xfrmnl_sel* xfrmnl_sel_get(struct xfrmnl_sel*);
+extern void xfrmnl_sel_put(struct xfrmnl_sel*);
+extern int xfrmnl_sel_shared(struct xfrmnl_sel*);
+extern int xfrmnl_sel_cmp(struct xfrmnl_sel*, struct xfrmnl_sel*);
+extern void xfrmnl_sel_dump(struct xfrmnl_sel*, struct nl_dump_params *);
+
+/* Access Functions */
+extern struct nl_addr* xfrmnl_sel_get_daddr (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_daddr (struct xfrmnl_sel*, struct nl_addr*);
+
+extern struct nl_addr* xfrmnl_sel_get_saddr (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_saddr (struct xfrmnl_sel*, struct nl_addr*);
+
+extern int xfrmnl_sel_get_dport (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_dport (struct xfrmnl_sel*, unsigned int);
+
+extern int xfrmnl_sel_get_dportmask (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_dportmask (struct xfrmnl_sel*, unsigned int);
+
+extern int xfrmnl_sel_get_sport (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_sport (struct xfrmnl_sel*, unsigned int);
+
+extern int xfrmnl_sel_get_sportmask (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_sportmask (struct xfrmnl_sel*, unsigned int);
+
+extern int xfrmnl_sel_get_family (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_family (struct xfrmnl_sel*, unsigned int);
+
+extern int xfrmnl_sel_get_prefixlen_d (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_prefixlen_d (struct xfrmnl_sel*, unsigned int);
+
+extern int xfrmnl_sel_get_prefixlen_s (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_prefixlen_s (struct xfrmnl_sel*, unsigned int);
+
+extern int xfrmnl_sel_get_proto (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_proto (struct xfrmnl_sel*, unsigned int);
+
+extern int xfrmnl_sel_get_ifindex (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_ifindex (struct xfrmnl_sel*, unsigned int);
+
+extern int xfrmnl_sel_get_userid (struct xfrmnl_sel*);
+extern int xfrmnl_sel_set_userid (struct xfrmnl_sel*, unsigned int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/xfrm/sp.h b/include/netlink/xfrm/sp.h
new file mode 100644
index 00000000..84cbfb26
--- /dev/null
+++ b/include/netlink/xfrm/sp.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+#ifndef NETLINK_XFRM_SP_H_
+#define NETLINK_XFRM_SP_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <netlink/xfrm/template.h>
+#include <netlink/xfrm/lifetime.h>
+#include <linux/xfrm.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xfrmnl_sp;
+
+extern struct xfrmnl_sp* xfrmnl_sp_alloc(void);
+extern void xfrmnl_sp_put(struct xfrmnl_sp *);
+
+extern int xfrmnl_sp_alloc_cache(struct nl_sock *, struct nl_cache **);
+extern struct xfrmnl_sp* xfrmnl_sp_get(struct nl_cache*, unsigned int, unsigned int);
+
+extern int xfrmnl_sp_parse(struct nlmsghdr *n, struct xfrmnl_sp **result);
+
+extern int xfrmnl_sp_build_get_request(unsigned int, unsigned int, unsigned int,
+ unsigned int, struct nl_msg **);
+extern int xfrmnl_sp_get_kernel(struct nl_sock*, unsigned int, unsigned int,
+ unsigned int, unsigned int, struct xfrmnl_sp**);
+
+extern int xfrmnl_sp_add(struct nl_sock*, struct xfrmnl_sp*, int);
+extern int xfrmnl_sp_build_add_request(struct xfrmnl_sp*, int, struct nl_msg **);
+
+extern int xfrmnl_sp_update(struct nl_sock*, struct xfrmnl_sp*, int);
+extern int xfrmnl_sp_build_update_request(struct xfrmnl_sp*, int, struct nl_msg **);
+
+extern int xfrmnl_sp_delete(struct nl_sock*, struct xfrmnl_sp*, int);
+extern int xfrmnl_sp_build_delete_request(struct xfrmnl_sp*, int, struct nl_msg **);
+
+extern struct xfrmnl_sel* xfrmnl_sp_get_sel (struct xfrmnl_sp*);
+extern int xfrmnl_sp_set_sel (struct xfrmnl_sp*, struct xfrmnl_sel*);
+
+extern struct xfrmnl_ltime_cfg* xfrmnl_sp_get_lifetime_cfg (struct xfrmnl_sp*);
+extern int xfrmnl_sp_set_lifetime_cfg (struct xfrmnl_sp*, struct xfrmnl_ltime_cfg*);
+
+extern int xfrmnl_sp_get_curlifetime (struct xfrmnl_sp*, unsigned long long int*,
+ unsigned long long int*, unsigned long long int*,
+ unsigned long long int*);
+
+extern int xfrmnl_sp_get_priority (struct xfrmnl_sp*);
+extern int xfrmnl_sp_set_priority (struct xfrmnl_sp*, unsigned int);
+
+extern int xfrmnl_sp_get_index (struct xfrmnl_sp*);
+extern int xfrmnl_sp_set_index (struct xfrmnl_sp*, unsigned int);
+
+extern int xfrmnl_sp_get_dir (struct xfrmnl_sp*);
+extern int xfrmnl_sp_set_dir (struct xfrmnl_sp*, unsigned int);
+
+extern int xfrmnl_sp_get_action (struct xfrmnl_sp*);
+extern int xfrmnl_sp_set_action (struct xfrmnl_sp*, unsigned int);
+
+extern int xfrmnl_sp_get_flags (struct xfrmnl_sp*);
+extern int xfrmnl_sp_set_flags (struct xfrmnl_sp*, unsigned int);
+
+extern int xfrmnl_sp_get_share (struct xfrmnl_sp*);
+extern int xfrmnl_sp_set_share (struct xfrmnl_sp*, unsigned int);
+
+extern int xfrmnl_sp_get_sec_ctx (struct xfrmnl_sp*, unsigned int*, unsigned int*,
+ unsigned int*, unsigned int*, unsigned int*, char*);
+extern int xfrmnl_sp_set_sec_ctx (struct xfrmnl_sp*, unsigned int, unsigned int,
+ unsigned int, unsigned int, unsigned int, char*);
+
+extern int xfrmnl_sp_get_userpolicy_type (struct xfrmnl_sp*);
+extern int xfrmnl_sp_set_userpolicy_type (struct xfrmnl_sp*, unsigned int);
+
+extern void xfrmnl_sp_add_usertemplate(struct xfrmnl_sp*, struct xfrmnl_user_tmpl*);
+extern void xfrmnl_sp_remove_usertemplate(struct xfrmnl_sp*, struct xfrmnl_user_tmpl*);
+extern struct nl_list_head* xfrmnl_sp_get_usertemplates(struct xfrmnl_sp*);
+extern int xfrmnl_sp_get_nusertemplates(struct xfrmnl_sp*);
+extern void xfrmnl_sp_foreach_usertemplate(struct xfrmnl_sp*,
+ void (*cb)(struct xfrmnl_user_tmpl*, void *),
+ void *arg);
+extern struct xfrmnl_user_tmpl* xfrmnl_sp_usertemplate_n(struct xfrmnl_sp*, int);
+
+extern int xfrmnl_sp_get_mark (struct xfrmnl_sp*, unsigned int*, unsigned int*);
+extern int xfrmnl_sp_set_mark (struct xfrmnl_sp*, unsigned int, unsigned int);
+
+extern char* xfrmnl_sp_action2str(int, char *, size_t);
+extern int xfrmnl_sp_str2action(const char *);
+
+extern char* xfrmnl_sp_flags2str(int, char *, size_t);
+extern int xfrmnl_sp_str2flag(const char *);
+
+extern char* xfrmnl_sp_type2str(int, char *, size_t);
+extern int xfrmnl_sp_str2type(const char *);
+
+extern char* xfrmnl_sp_dir2str(int, char *, size_t);
+extern int xfrmnl_sp_str2dir(const char *);
+
+extern char* xfrmnl_sp_share2str(int, char *, size_t);
+extern int xfrmnl_sp_str2share(const char *);
+
+extern int xfrmnl_sp_index2dir (unsigned int);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/netlink/xfrm/template.h b/include/netlink/xfrm/template.h
new file mode 100644
index 00000000..da51e7d8
--- /dev/null
+++ b/include/netlink/xfrm/template.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+#ifndef NETLINK_XFRM_TEMPL_H_
+#define NETLINK_XFRM_TEMPL_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/addr.h>
+#include <linux/xfrm.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct xfrmnl_user_tmpl;
+
+/* Creation */
+extern struct xfrmnl_user_tmpl* xfrmnl_user_tmpl_alloc(void);
+extern struct xfrmnl_user_tmpl* xfrmnl_user_tmpl_clone(struct xfrmnl_user_tmpl*);
+extern void xfrmnl_user_tmpl_free(struct xfrmnl_user_tmpl* utmpl);
+
+/* Utility functions */
+extern int xfrmnl_user_tmpl_cmp(struct xfrmnl_user_tmpl*, struct xfrmnl_user_tmpl*);
+extern void xfrmnl_user_tmpl_dump(struct xfrmnl_user_tmpl*, struct nl_dump_params*);
+
+/* Access Functions */
+extern struct nl_addr* xfrmnl_user_tmpl_get_daddr (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_daddr (struct xfrmnl_user_tmpl*, struct nl_addr*);
+
+extern int xfrmnl_user_tmpl_get_spi (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_spi (struct xfrmnl_user_tmpl*, unsigned int);
+
+extern int xfrmnl_user_tmpl_get_proto (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_proto (struct xfrmnl_user_tmpl*, unsigned int);
+
+extern int xfrmnl_user_tmpl_get_family (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_family (struct xfrmnl_user_tmpl*, unsigned int);
+
+extern struct nl_addr* xfrmnl_user_tmpl_get_saddr (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_saddr (struct xfrmnl_user_tmpl*, struct nl_addr*);
+
+extern int xfrmnl_user_tmpl_get_reqid (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_reqid (struct xfrmnl_user_tmpl*, unsigned int);
+
+extern int xfrmnl_user_tmpl_get_mode (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_mode (struct xfrmnl_user_tmpl*, unsigned int);
+
+extern int xfrmnl_user_tmpl_get_share (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_share (struct xfrmnl_user_tmpl*, unsigned int);
+
+extern int xfrmnl_user_tmpl_get_optional (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_optional (struct xfrmnl_user_tmpl*, unsigned int);
+
+extern int xfrmnl_user_tmpl_get_aalgos (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_aalgos (struct xfrmnl_user_tmpl*, unsigned int);
+
+extern int xfrmnl_user_tmpl_get_ealgos (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_ealgos (struct xfrmnl_user_tmpl*, unsigned int);
+
+extern int xfrmnl_user_tmpl_get_calgos (struct xfrmnl_user_tmpl*);
+extern int xfrmnl_user_tmpl_set_calgos (struct xfrmnl_user_tmpl*, unsigned int);
+
+extern char* xfrmnl_user_tmpl_mode2str(int, char *, size_t);
+extern int xfrmnl_user_tmpl_str2mode(const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/Makefile.am b/lib/Makefile.am
deleted file mode 100644
index bc8944d3..00000000
--- a/lib/Makefile.am
+++ /dev/null
@@ -1,135 +0,0 @@
-# -*- Makefile -*-
-
-AM_CPPFLAGS = \
- -Wall \
- -I${top_srcdir}/include/linux-private \
- -I${top_srcdir}/include \
- -I${top_builddir}/include \
- -I${builddir}/route \
- -I${builddir}/route/cls \
- -D_GNU_SOURCE \
- -DSYSCONFDIR=\"$(sysconfdir)/libnl\"
-
-AM_LDFLAGS = \
- -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
- -Wl,--version-script=$(top_builddir)/libnl.sym
-
-lib_LTLIBRARIES = \
- libnl-3.la libnl-genl-3.la libnl-route-3.la libnl-nf-3.la libnl-idiag-3.la
-
-libnl_3_la_SOURCES = \
- addr.c attr.c cache.c cache_mngr.c cache_mngt.c data.c \
- error.c handlers.c msg.c nl.c object.c socket.c utils.c \
- version.c hash.c hashtable.c
-
-libnl_idiag_3_la_LIBADD = libnl-3.la
-libnl_idiag_3_la_SOURCES = \
- idiag/idiag_meminfo_obj.c idiag/idiag_vegasinfo_obj.c \
- idiag/idiag_msg_obj.c idiag/idiag_req_obj.c idiag/idiag.c
-
-libnl_genl_3_la_LIBADD = libnl-3.la
-libnl_genl_3_la_SOURCES = \
- genl/ctrl.c genl/family.c genl/genl.c genl/mngt.c
-
-libnl_nf_3_la_LIBADD = libnl-route-3.la
-libnl_nf_3_la_SOURCES = \
- netfilter/ct.c netfilter/ct_obj.c netfilter/log.c \
- netfilter/log_msg.c netfilter/log_msg_obj.c netfilter/log_obj.c \
- netfilter/netfilter.c netfilter/nfnl.c netfilter/queue.c \
- netfilter/queue_msg.c netfilter/queue_msg_obj.c netfilter/queue_obj.c \
- netfilter/exp.c netfilter/exp_obj.c
-
-CLEANFILES = \
- route/pktloc_grammar.c route/pktloc_grammar.h \
- route/pktloc_syntax.c route/pktloc_syntax.h \
- route/cls/ematch_grammar.c route/cls/ematch_grammar.h \
- route/cls/ematch_syntax.c route/cls/ematch_syntax.h
-
-# Hack to avoid using ylwrap. It does not function correctly in combination
-# with --header-file=
-route/pktloc_grammar.c: route/pktloc_grammar.l
- $(AM_V_GEN) $(MKDIR_P) route; $(FLEX) --header-file=route/pktloc_grammar.h $(LFLAGS) -o $@ $^
-
-route/pktloc_syntax.c: route/pktloc_syntax.y
- $(AM_V_GEN) $(MKDIR_P) route; $(YACC) -d $(YFLAGS) -o $@ $^
-
-route/cls/ematch_grammar.c: route/cls/ematch_grammar.l
- $(AM_V_GEN) $(MKDIR_P) route/cls; $(FLEX) --header-file=route/cls/ematch_grammar.h $(LFLAGS) -o $@ $^
-
-route/cls/ematch_syntax.c: route/cls/ematch_syntax.y
- $(AM_V_GEN) $(MKDIR_P) route/cls; $(YACC) -d $(YFLAGS) -o $@ $^
-
-libnl_route_3_la_LIBADD = libnl-3.la
-libnl_route_3_la_SOURCES = \
- route/addr.c route/class.c route/cls.c route/act.c route/link.c \
- route/neigh.c route/neightbl.c route/nexthop.c route/qdisc.c \
- route/route.c route/route_obj.c route/route_utils.c route/rtnl.c \
- route/rule.c route/tc.c route/classid.c \
- \
- route/cls/fw.c route/cls/police.c route/cls/u32.c route/cls/basic.c \
- route/cls/cgroup.c \
- \
- route/act/mirred.c \
- \
- route/cls/ematch.c \
- route/cls/ematch/container.c route/cls/ematch/cmp.c \
- route/cls/ematch/nbyte.c route/cls/ematch/text.c \
- route/cls/ematch/meta.c \
- \
- route/link/api.c route/link/vlan.c route/link/dummy.c \
- route/link/bridge.c route/link/inet6.c route/link/inet.c \
- route/link/bonding.c route/link/can.c route/link/macvlan.c \
- route/link/vxlan.c route/link/veth.c route/link/ipip.c \
- route/link/ipgre.c route/link/sit.c route/link/ipvti.c \
- route/link/ip6tnl.c \
- \
- route/qdisc/blackhole.c route/qdisc/cbq.c route/qdisc/dsmark.c \
- route/qdisc/fifo.c route/qdisc/htb.c route/qdisc/netem.c \
- route/qdisc/prio.c route/qdisc/red.c route/qdisc/sfq.c \
- route/qdisc/tbf.c route/qdisc/plug.c route/qdisc/ingress.c \
- route/qdisc/fq_codel.c \
- \
- fib_lookup/lookup.c fib_lookup/request.c \
- \
- route/pktloc.c
-
-nodist_libnl_route_3_la_SOURCES = \
- route/pktloc_syntax.c route/pktloc_syntax.h \
- route/pktloc_grammar.c route/pktloc_grammar.h \
- route/cls/ematch_syntax.c route/cls/ematch_syntax.h \
- route/cls/ematch_grammar.c route/cls/ematch_grammar.h
-
-BUILT_SOURCES = \
- route/cls/ematch_grammar.c \
- route/cls/ematch_syntax.c \
- route/pktloc_grammar.c \
- route/pktloc_syntax.c
-
-EXTRA_DIST = \
- route/pktloc_grammar.l \
- route/pktloc_syntax.y \
- route/cls/ematch_grammar.l \
- route/cls/ematch_syntax.y
-
-if ENABLE_CLI
-nobase_pkglib_LTLIBRARIES = \
- cli/qdisc/htb.la \
- cli/qdisc/blackhole.la \
- cli/qdisc/pfifo.la \
- cli/qdisc/plug.la \
- cli/qdisc/bfifo.la \
- cli/qdisc/ingress.la \
- cli/qdisc/fq_codel.la \
- cli/cls/basic.la \
- cli/cls/cgroup.la
-
-cli_qdisc_htb_la_LDFLAGS = -module -avoid-version
-cli_qdisc_blackhole_la_LDFLAGS = -module -avoid-version
-cli_qdisc_pfifo_la_LDFLAGS = -module -avoid-version
-cli_qdisc_plug_la_LDFLAGS = -module -avoid-version
-cli_qdisc_bfifo_la_LDFLAGS = -module -avoid-version
-cli_qdisc_ingress_la_LDFLAGS = -module -avoid-version
-cli_qdisc_fq_codel_la_LDFLAGS = -module -avoid-version
-cli_cls_basic_la_LDFLAGS = -module -avoid-version
-cli_cls_cgroup_la_LDFLAGS = -module -avoid-version
-endif
diff --git a/lib/addr.c b/lib/addr.c
index 54d2b1db..06f31383 100644
--- a/lib/addr.c
+++ b/lib/addr.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/addr.c Network Address
*
@@ -31,6 +32,7 @@
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/addr.h>
+#include <netlink-private/route/mpls.h>
#include <linux/socket.h>
/* All this DECnet stuff is stolen from iproute2, thanks to whoever wrote
@@ -65,7 +67,7 @@ static inline int do_digit(char *str, uint16_t *addr, uint16_t scale,
return 0;
}
-static const char *dnet_ntop(char *addrbuf, size_t addrlen, char *str,
+static const char *dnet_ntop(const char *addrbuf, size_t addrlen, char *str,
size_t len)
{
uint16_t addr = dn_ntohs(*(uint16_t *)addrbuf);
@@ -213,7 +215,7 @@ struct nl_addr *nl_addr_alloc(size_t maxsize)
*
* @return Allocated address object or NULL upon failure.
*/
-struct nl_addr *nl_addr_build(int family, void *buf, size_t size)
+struct nl_addr *nl_addr_build(int family, const void *buf, size_t size)
{
struct nl_addr *addr;
@@ -223,7 +225,13 @@ struct nl_addr *nl_addr_build(int family, void *buf, size_t size)
addr->a_family = family;
addr->a_len = size;
- addr->a_prefixlen = size*8;
+ switch(family) {
+ case AF_MPLS:
+ addr->a_prefixlen = 20; /* MPLS address is a 20-bit label */
+ break;
+ default:
+ addr->a_prefixlen = size*8;
+ }
if (size)
memcpy(addr->a_addr, buf, size);
@@ -252,7 +260,7 @@ struct nl_addr *nl_addr_build(int family, void *buf, size_t size)
*
* @return Allocated address object or NULL upon failure.
*/
-struct nl_addr *nl_addr_alloc_attr(struct nlattr *nla, int family)
+struct nl_addr *nl_addr_alloc_attr(const struct nlattr *nla, int family)
{
return nl_addr_build(family, nla_data(nla), nla_len(nla));
}
@@ -290,8 +298,8 @@ struct nl_addr *nl_addr_alloc_attr(struct nlattr *nla, int family)
*/
int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result)
{
- int err, copy = 0, len = 0, family = AF_UNSPEC;
- char *str, *prefix, buf[32];
+ int err, copy = 0, len = 0, family = AF_UNSPEC, plen = 0;
+ char *str, *prefix = NULL, buf[256];
struct nl_addr *addr = NULL; /* gcc ain't that smart */
str = strdup(addrstr);
@@ -300,9 +308,11 @@ int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result)
goto errout;
}
- prefix = strchr(str, '/');
- if (prefix)
- *prefix = '\0';
+ if (hint != AF_MPLS) {
+ prefix = strchr(str, '/');
+ if (prefix)
+ *prefix = '\0';
+ }
if (!strcasecmp(str, "none")) {
family = hint;
@@ -399,6 +409,17 @@ int nl_addr_parse(const char *addrstr, int hint, struct nl_addr **result)
}
}
+ if (hint == AF_MPLS) {
+ len = mpls_pton(AF_MPLS, str, buf, sizeof(buf));
+ if (len <= 0) {
+ err = -NLE_INVAL;
+ goto errout;
+ }
+ family = AF_MPLS;
+ plen = 20;
+ goto prefix;
+ }
+
if (hint == AF_UNSPEC && strchr(str, ':')) {
size_t i = 0;
char *s = str, *p;
@@ -445,9 +466,11 @@ prefix:
goto errout;
}
nl_addr_set_prefixlen(addr, pl);
- } else
- nl_addr_set_prefixlen(addr, len * 8);
-
+ } else {
+ if (!plen)
+ plen = len * 8;
+ nl_addr_set_prefixlen(addr, plen);
+ }
*result = addr;
err = 0;
errout:
@@ -468,7 +491,7 @@ errout:
*
* @return Allocated abstract address or NULL upon failure.
*/
-struct nl_addr *nl_addr_clone(struct nl_addr *addr)
+struct nl_addr *nl_addr_clone(const struct nl_addr *addr)
{
struct nl_addr *new;
@@ -531,7 +554,7 @@ void nl_addr_put(struct nl_addr *addr)
*
* @return Non-zero if the abstract address is shared, otherwise 0.
*/
-int nl_addr_shared(struct nl_addr *addr)
+int nl_addr_shared(const struct nl_addr *addr)
{
return addr->a_refcnt > 1;
}
@@ -560,10 +583,18 @@ int nl_addr_shared(struct nl_addr *addr)
* @return Integer less than, equal to or greather than zero if the two
* addresses match.
*/
-int nl_addr_cmp(struct nl_addr *a, struct nl_addr *b)
+int nl_addr_cmp(const struct nl_addr *a, const struct nl_addr *b)
{
- int d = a->a_family - b->a_family;
+ int d;
+
+ if (a == b)
+ return 0;
+ if (!a)
+ return -1;
+ if (!b)
+ return 1;
+ d = a->a_family - b->a_family;
if (d == 0) {
d = a->a_len - b->a_len;
@@ -591,7 +622,7 @@ int nl_addr_cmp(struct nl_addr *a, struct nl_addr *b)
* @return Integer less than, equal to or greather than zero if the two
* addresses match.
*/
-int nl_addr_cmp_prefix(struct nl_addr *a, struct nl_addr *b)
+int nl_addr_cmp_prefix(const struct nl_addr *a, const struct nl_addr *b)
{
int d = a->a_family - b->a_family;
@@ -617,7 +648,7 @@ int nl_addr_cmp_prefix(struct nl_addr *a, struct nl_addr *b)
*
* @return 1 if the binary address consists of all zeros, 0 otherwise.
*/
-int nl_addr_iszero(struct nl_addr *addr)
+int nl_addr_iszero(const struct nl_addr *addr)
{
unsigned int i;
@@ -636,10 +667,10 @@ int nl_addr_iszero(struct nl_addr *addr)
* @return 1 if the address is parseable assuming the specified address family,
* otherwise 0 is returned.
*/
-int nl_addr_valid(char *addr, int family)
+int nl_addr_valid(const char *addr, int family)
{
int ret;
- char buf[32];
+ char buf[256]; /* MPLS has N-labels at 4-bytes / label */
switch (family) {
case AF_INET:
@@ -649,6 +680,12 @@ int nl_addr_valid(char *addr, int family)
return 0;
break;
+ case AF_MPLS:
+ ret = mpls_pton(family, addr, buf, sizeof(buf));
+ if (ret <= 0)
+ return 0;
+ break;
+
case AF_DECnet:
ret = dnet_pton(addr, buf);
if (ret <= 0)
@@ -670,7 +707,7 @@ int nl_addr_valid(char *addr, int family)
*
* @return Numeric address family or AF_UNSPEC
*/
-int nl_addr_guess_family(struct nl_addr *addr)
+int nl_addr_guess_family(const struct nl_addr *addr)
{
switch (addr->a_len) {
case 4:
@@ -697,7 +734,7 @@ int nl_addr_guess_family(struct nl_addr *addr)
*
* @return 0 on success or a negative error code
*/
-int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa,
+int nl_addr_fill_sockaddr(const struct nl_addr *addr, struct sockaddr *sa,
socklen_t *salen)
{
switch (addr->a_family) {
@@ -707,8 +744,14 @@ int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa,
if (*salen < sizeof(*sai))
return -NLE_INVAL;
+ if (addr->a_len == 4)
+ memcpy(&sai->sin_addr, addr->a_addr, 4);
+ else if (addr->a_len != 0)
+ return -NLE_INVAL;
+ else
+ memset(&sai->sin_addr, 0, 4);
+
sai->sin_family = addr->a_family;
- memcpy(&sai->sin_addr, addr->a_addr, 4);
*salen = sizeof(*sai);
}
break;
@@ -719,8 +762,14 @@ int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa,
if (*salen < sizeof(*sa6))
return -NLE_INVAL;
+ if (addr->a_len == 16)
+ memcpy(&sa6->sin6_addr, addr->a_addr, 16);
+ else if (addr->a_len != 0)
+ return -NLE_INVAL;
+ else
+ memset(&sa6->sin6_addr, 0, 16);
+
sa6->sin6_family = addr->a_family;
- memcpy(&sa6->sin6_addr, addr->a_addr, 16);
*salen = sizeof(*sa6);
}
break;
@@ -753,7 +802,7 @@ int nl_addr_fill_sockaddr(struct nl_addr *addr, struct sockaddr *sa,
*
* @return 0 on success or a negative error code.
*/
-int nl_addr_info(struct nl_addr *addr, struct addrinfo **result)
+int nl_addr_info(const struct nl_addr *addr, struct addrinfo **result)
{
int err;
char buf[INET6_ADDRSTRLEN+5];
@@ -797,7 +846,7 @@ int nl_addr_info(struct nl_addr *addr, struct addrinfo **result)
*
* @return 0 on success or a negative error code.
*/
-int nl_addr_resolve(struct nl_addr *addr, char *host, size_t hostlen)
+int nl_addr_resolve(const struct nl_addr *addr, char *host, size_t hostlen)
{
int err;
struct sockaddr_in6 buf;
@@ -842,7 +891,7 @@ void nl_addr_set_family(struct nl_addr *addr, int family)
*
* @return The numeric address family or `AF_UNSPEC`
*/
-int nl_addr_get_family(struct nl_addr *addr)
+int nl_addr_get_family(const struct nl_addr *addr)
{
return addr->a_family;
}
@@ -867,7 +916,7 @@ int nl_addr_get_family(struct nl_addr *addr)
*
* @return 0 on success or a negative error code.
*/
-int nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len)
+int nl_addr_set_binary_addr(struct nl_addr *addr, const void *buf, size_t len)
{
if (len > addr->a_maxsize)
return -NLE_RANGE;
@@ -890,9 +939,9 @@ int nl_addr_set_binary_addr(struct nl_addr *addr, void *buf, size_t len)
*
* @return Pointer to binary address of length nl_addr_get_len()
*/
-void *nl_addr_get_binary_addr(struct nl_addr *addr)
+void *nl_addr_get_binary_addr(const struct nl_addr *addr)
{
- return addr->a_addr;
+ return (void*)addr->a_addr;
}
/**
@@ -902,7 +951,7 @@ void *nl_addr_get_binary_addr(struct nl_addr *addr)
* @see nl_addr_get_binary_addr()
* @see nl_addr_set_binary_addr()
*/
-unsigned int nl_addr_get_len(struct nl_addr *addr)
+unsigned int nl_addr_get_len(const struct nl_addr *addr)
{
return addr->a_len;
}
@@ -925,7 +974,7 @@ void nl_addr_set_prefixlen(struct nl_addr *addr, int prefixlen)
*
* @see nl_addr_set_prefixlen()
*/
-unsigned int nl_addr_get_prefixlen(struct nl_addr *addr)
+unsigned int nl_addr_get_prefixlen(const struct nl_addr *addr)
{
return addr->a_prefixlen;
}
@@ -948,7 +997,7 @@ unsigned int nl_addr_get_prefixlen(struct nl_addr *addr)
*
* @return Address represented in ASCII stored in destination buffer.
*/
-char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size)
+char *nl_addr2str(const struct nl_addr *addr, char *buf, size_t size)
{
unsigned int i;
char tmp[16];
@@ -970,6 +1019,10 @@ char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size)
inet_ntop(AF_INET6, addr->a_addr, buf, size);
break;
+ case AF_MPLS:
+ mpls_ntop(AF_MPLS, addr->a_addr, buf, size);
+ break;
+
case AF_DECnet:
dnet_ntop(addr->a_addr, addr->a_len, buf, size);
break;
@@ -987,7 +1040,8 @@ char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size)
}
prefix:
- if (addr->a_prefixlen != (8 * addr->a_len)) {
+ if (addr->a_family != AF_MPLS &&
+ addr->a_prefixlen != (8 * addr->a_len)) {
snprintf(tmp, sizeof(tmp), "/%u", addr->a_prefixlen);
strncat(buf, tmp, size - strlen(buf) - 1);
}
@@ -1003,66 +1057,70 @@ prefix:
*/
static const struct trans_tbl afs[] = {
- __ADD(AF_UNSPEC,unspec)
- __ADD(AF_UNIX,unix)
- __ADD(AF_INET,inet)
- __ADD(AF_AX25,ax25)
- __ADD(AF_IPX,ipx)
- __ADD(AF_APPLETALK,appletalk)
- __ADD(AF_NETROM,netrom)
- __ADD(AF_BRIDGE,bridge)
- __ADD(AF_ATMPVC,atmpvc)
- __ADD(AF_X25,x25)
- __ADD(AF_INET6,inet6)
- __ADD(AF_ROSE,rose)
- __ADD(AF_DECnet,decnet)
- __ADD(AF_NETBEUI,netbeui)
- __ADD(AF_SECURITY,security)
- __ADD(AF_KEY,key)
- __ADD(AF_NETLINK,netlink)
- __ADD(AF_PACKET,packet)
- __ADD(AF_ASH,ash)
- __ADD(AF_ECONET,econet)
- __ADD(AF_ATMSVC,atmsvc)
+ __ADD(AF_UNSPEC,unspec),
+ __ADD(AF_UNIX,unix),
+ __ADD(AF_INET,inet),
+ __ADD(AF_AX25,ax25),
+ __ADD(AF_IPX,ipx),
+ __ADD(AF_APPLETALK,appletalk),
+ __ADD(AF_NETROM,netrom),
+ __ADD(AF_BRIDGE,bridge),
+ __ADD(AF_ATMPVC,atmpvc),
+ __ADD(AF_X25,x25),
+ __ADD(AF_INET6,inet6),
+ __ADD(AF_ROSE,rose),
+ __ADD(AF_DECnet,decnet),
+ __ADD(AF_NETBEUI,netbeui),
+ __ADD(AF_SECURITY,security),
+ __ADD(AF_KEY,key),
+ __ADD(AF_NETLINK,netlink),
+ __ADD(AF_PACKET,packet),
+ __ADD(AF_ASH,ash),
+ __ADD(AF_ECONET,econet),
+ __ADD(AF_ATMSVC,atmsvc),
#ifdef AF_RDS
- __ADD(AF_RDS,rds)
+ __ADD(AF_RDS,rds),
#endif
- __ADD(AF_SNA,sna)
- __ADD(AF_IRDA,irda)
- __ADD(AF_PPPOX,pppox)
- __ADD(AF_WANPIPE,wanpipe)
- __ADD(AF_LLC,llc)
+ __ADD(AF_SNA,sna),
+ __ADD(AF_IRDA,irda),
+ __ADD(AF_PPPOX,pppox),
+ __ADD(AF_WANPIPE,wanpipe),
+ __ADD(AF_LLC,llc),
#ifdef AF_CAN
- __ADD(AF_CAN,can)
+ __ADD(AF_CAN,can),
#endif
#ifdef AF_TIPC
- __ADD(AF_TIPC,tipc)
+ __ADD(AF_TIPC,tipc),
#endif
- __ADD(AF_BLUETOOTH,bluetooth)
+ __ADD(AF_BLUETOOTH,bluetooth),
#ifdef AF_IUCV
- __ADD(AF_IUCV,iucv)
+ __ADD(AF_IUCV,iucv),
#endif
#ifdef AF_RXRPC
- __ADD(AF_RXRPC,rxrpc)
+ __ADD(AF_RXRPC,rxrpc),
#endif
#ifdef AF_ISDN
- __ADD(AF_ISDN,isdn)
+ __ADD(AF_ISDN,isdn),
#endif
#ifdef AF_PHONET
- __ADD(AF_PHONET,phonet)
+ __ADD(AF_PHONET,phonet),
#endif
#ifdef AF_IEEE802154
- __ADD(AF_IEEE802154,ieee802154)
+ __ADD(AF_IEEE802154,ieee802154),
#endif
#ifdef AF_CAIF
- __ADD(AF_CAIF,caif)
+ __ADD(AF_CAIF,caif),
#endif
#ifdef AF_ALG
- __ADD(AF_ALG,alg)
+ __ADD(AF_ALG,alg),
#endif
#ifdef AF_NFC
- __ADD(AF_NFC,nfc)
+ __ADD(AF_NFC,nfc),
+#endif
+#ifdef AF_VSOCK
+ __ADD(AF_VSOCK,vsock),
#endif
+ __ADD(AF_MPLS,mpls),
};
char *nl_af2str(int family, char *buf, size_t size)
diff --git a/lib/attr.c b/lib/attr.c
index a76a2842..a4f58527 100644
--- a/lib/attr.c
+++ b/lib/attr.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/attr.c Netlink Attributes
*
@@ -147,7 +148,7 @@ int nla_len(const struct nlattr *nla)
*/
int nla_ok(const struct nlattr *nla, int remaining)
{
- return remaining >= sizeof(*nla) &&
+ return remaining >= (int) sizeof(*nla) &&
nla->nla_len >= sizeof(*nla) &&
nla->nla_len <= remaining;
}
@@ -185,10 +186,10 @@ static uint16_t nla_attr_minlen[NLA_TYPE_MAX+1] = {
[NLA_FLAG] = 0,
};
-static int validate_nla(struct nlattr *nla, int maxtype,
- struct nla_policy *policy)
+static int validate_nla(const struct nlattr *nla, int maxtype,
+ const struct nla_policy *policy)
{
- struct nla_policy *pt;
+ const struct nla_policy *pt;
unsigned int minlen = 0;
int type = nla_type(nla);
@@ -212,7 +213,7 @@ static int validate_nla(struct nlattr *nla, int maxtype,
return -NLE_RANGE;
if (pt->type == NLA_STRING) {
- char *data = nla_data(nla);
+ const char *data = nla_data(nla);
if (data[nla_len(nla) - 1] != '\0')
return -NLE_INVAL;
}
@@ -240,7 +241,7 @@ static int validate_nla(struct nlattr *nla, int maxtype,
* @return 0 on success or a negative error code.
*/
int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len,
- struct nla_policy *policy)
+ const struct nla_policy *policy)
{
struct nlattr *nla;
int rem, err;
@@ -291,10 +292,10 @@ errout:
*
* @return 0 on success or a negative error code.
*/
-int nla_validate(struct nlattr *head, int len, int maxtype,
- struct nla_policy *policy)
+int nla_validate(const struct nlattr *head, int len, int maxtype,
+ const struct nla_policy *policy)
{
- struct nlattr *nla;
+ const struct nlattr *nla;
int rem, err;
nla_for_each_attr(nla, head, len, rem) {
@@ -320,14 +321,14 @@ errout:
*
* @return Pointer to attribute found or NULL.
*/
-struct nlattr *nla_find(struct nlattr *head, int len, int attrtype)
+struct nlattr *nla_find(const struct nlattr *head, int len, int attrtype)
{
- struct nlattr *nla;
+ const struct nlattr *nla;
int rem;
nla_for_each_attr(nla, head, len, rem)
if (nla_type(nla) == attrtype)
- return nla;
+ return (struct nlattr*)nla;
return NULL;
}
@@ -350,7 +351,7 @@ struct nlattr *nla_find(struct nlattr *head, int len, int attrtype)
*
* @return The number of bytes copied to dest.
*/
-int nla_memcpy(void *dest, struct nlattr *src, int count)
+int nla_memcpy(void *dest, const struct nlattr *src, int count)
{
int minlen;
@@ -378,7 +379,7 @@ int nla_memcpy(void *dest, struct nlattr *src, int count)
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
{
size_t srclen = nla_len(nla);
- char *src = nla_data(nla);
+ const char *src = nla_data(nla);
if (srclen > 0 && src[srclen - 1] == '\0')
srclen--;
@@ -457,7 +458,7 @@ struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen)
{
struct nlattr *nla;
int tlen;
-
+
if (attrlen < 0)
return NULL;
@@ -477,7 +478,7 @@ struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int attrlen)
NL_DBG(2, "msg %p: attr <%p> %d: Reserved %d (%d) bytes at offset +%td "
"nlmsg_len=%d\n", msg, nla, nla->nla_type,
nla_total_size(attrlen), attrlen,
- (void *) nla - nlmsg_data(msg->nm_nlh),
+ (char *) nla - (char *) nlmsg_data(msg->nm_nlh),
msg->nm_nlh->nlmsg_len);
return nla;
@@ -501,18 +502,19 @@ int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
{
struct nlattr *nla;
- if (datalen < 0)
- return -NLE_RANGE;
-
nla = nla_reserve(msg, attrtype, datalen);
- if (!nla)
+ if (!nla) {
+ if (datalen < 0)
+ return -NLE_INVAL;
+
return -NLE_NOMEM;
+ }
if (datalen > 0) {
memcpy(nla_data(nla), data, datalen);
NL_DBG(2, "msg %p: attr <%p> %d: Wrote %d bytes at offset +%td\n",
msg, nla, nla->nla_type, datalen,
- (void *) nla - nlmsg_data(msg->nm_nlh));
+ (char *) nla - (char *) nlmsg_data(msg->nm_nlh));
}
return 0;
@@ -530,7 +532,7 @@ int nla_put(struct nl_msg *msg, int attrtype, int datalen, const void *data)
* @see nla_put
* @return 0 on success or a negative error code.
*/
-int nla_put_data(struct nl_msg *msg, int attrtype, struct nl_data *data)
+int nla_put_data(struct nl_msg *msg, int attrtype, const struct nl_data *data)
{
return nla_put(msg, attrtype, nl_data_get_size(data),
nl_data_get(data));
@@ -558,6 +560,31 @@ int nla_put_addr(struct nl_msg *msg, int attrtype, struct nl_addr *addr)
*/
/**
+ * Add 8 bit signed integer attribute to netlink message.
+ * @arg msg Netlink message.
+ * @arg attrtype Attribute type.
+ * @arg value Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_s8(struct nl_msg *msg, int attrtype, int8_t value)
+{
+ return nla_put(msg, attrtype, sizeof(int8_t), &value);
+}
+
+/**
+ * Return value of 8 bit signed integer attribute.
+ * @arg nla 8 bit integer attribute
+ *
+ * @return Payload as 8 bit integer.
+ */
+int8_t nla_get_s8(const struct nlattr *nla)
+{
+ return *(const int8_t *) nla_data(nla);
+}
+
+/**
* Add 8 bit integer attribute to netlink message.
* @arg msg Netlink message.
* @arg attrtype Attribute type.
@@ -577,9 +604,34 @@ int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value)
*
* @return Payload as 8 bit integer.
*/
-uint8_t nla_get_u8(struct nlattr *nla)
+uint8_t nla_get_u8(const struct nlattr *nla)
+{
+ return *(const uint8_t *) nla_data(nla);
+}
+
+/**
+ * Add 16 bit signed integer attribute to netlink message.
+ * @arg msg Netlink message.
+ * @arg attrtype Attribute type.
+ * @arg value Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_s16(struct nl_msg *msg, int attrtype, int16_t value)
+{
+ return nla_put(msg, attrtype, sizeof(int16_t), &value);
+}
+
+/**
+ * Return payload of 16 bit signed integer attribute.
+ * @arg nla 16 bit integer attribute
+ *
+ * @return Payload as 16 bit integer.
+ */
+int16_t nla_get_s16(const struct nlattr *nla)
{
- return *(uint8_t *) nla_data(nla);
+ return *(const int16_t *) nla_data(nla);
}
/**
@@ -602,9 +654,34 @@ int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value)
*
* @return Payload as 16 bit integer.
*/
-uint16_t nla_get_u16(struct nlattr *nla)
+uint16_t nla_get_u16(const struct nlattr *nla)
+{
+ return *(const uint16_t *) nla_data(nla);
+}
+
+/**
+ * Add 32 bit signed integer attribute to netlink message.
+ * @arg msg Netlink message.
+ * @arg attrtype Attribute type.
+ * @arg value Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_s32(struct nl_msg *msg, int attrtype, int32_t value)
+{
+ return nla_put(msg, attrtype, sizeof(int32_t), &value);
+}
+
+/**
+ * Return payload of 32 bit signed integer attribute.
+ * @arg nla 32 bit integer attribute.
+ *
+ * @return Payload as 32 bit integer.
+ */
+int32_t nla_get_s32(const struct nlattr *nla)
{
- return *(uint16_t *) nla_data(nla);
+ return *(const int32_t *) nla_data(nla);
}
/**
@@ -627,9 +704,39 @@ int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value)
*
* @return Payload as 32 bit integer.
*/
-uint32_t nla_get_u32(struct nlattr *nla)
+uint32_t nla_get_u32(const struct nlattr *nla)
{
- return *(uint32_t *) nla_data(nla);
+ return *(const uint32_t *) nla_data(nla);
+}
+
+/**
+ * Add 64 bit signed integer attribute to netlink message.
+ * @arg msg Netlink message.
+ * @arg attrtype Attribute type.
+ * @arg value Numeric value to store as payload.
+ *
+ * @see nla_put
+ * @return 0 on success or a negative error code.
+ */
+int nla_put_s64(struct nl_msg *msg, int attrtype, int64_t value)
+{
+ return nla_put(msg, attrtype, sizeof(int64_t), &value);
+}
+
+/**
+ * Return payload of s64 attribute
+ * @arg nla s64 netlink attribute
+ *
+ * @return Payload as 64 bit integer.
+ */
+int64_t nla_get_s64(const struct nlattr *nla)
+{
+ int64_t tmp = 0;
+
+ if (nla && nla_len(nla) >= sizeof(tmp))
+ memcpy(&tmp, nla_data(nla), sizeof(tmp));
+
+ return tmp;
}
/**
@@ -652,7 +759,7 @@ int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value)
*
* @return Payload as 64 bit integer.
*/
-uint64_t nla_get_u64(struct nlattr *nla)
+uint64_t nla_get_u64(const struct nlattr *nla)
{
uint64_t tmp = 0;
@@ -688,12 +795,12 @@ int nla_put_string(struct nl_msg *msg, int attrtype, const char *str)
*
* @return Pointer to attribute payload.
*/
-char *nla_get_string(struct nlattr *nla)
+char *nla_get_string(const struct nlattr *nla)
{
return (char *) nla_data(nla);
}
-char *nla_strdup(struct nlattr *nla)
+char *nla_strdup(const struct nlattr *nla)
{
return strdup(nla_get_string(nla));
}
@@ -723,7 +830,7 @@ int nla_put_flag(struct nl_msg *msg, int attrtype)
*
* @return True if flag is set, otherwise false.
*/
-int nla_get_flag(struct nlattr *nla)
+int nla_get_flag(const struct nlattr *nla)
{
return !!nla;
}
@@ -751,7 +858,7 @@ int nla_put_msecs(struct nl_msg *n, int attrtype, unsigned long msecs)
*
* @return the number of milliseconds.
*/
-unsigned long nla_get_msecs(struct nlattr *nla)
+unsigned long nla_get_msecs(const struct nlattr *nla)
{
return nla_get_u64(nla);
}
@@ -775,7 +882,8 @@ unsigned long nla_get_msecs(struct nlattr *nla)
* @see nla_put
* @return 0 on success or a negative error code.
*/
-int nla_put_nested(struct nl_msg *msg, int attrtype, struct nl_msg *nested)
+int nla_put_nested(struct nl_msg *msg, int attrtype,
+ const struct nl_msg *nested)
{
NL_DBG(2, "msg %p: attr <> %d: adding msg %p as nested attribute\n",
msg, attrtype, nested);
@@ -805,29 +913,22 @@ struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype)
return start;
}
-/**
- * Finalize nesting of attributes.
- * @arg msg Netlink message.
- * @arg start Container attribute as returned from nla_nest_start().
- *
- * Corrects the container attribute header to include the appeneded attributes.
- *
- * @return 0
- */
-int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
+static int _nest_end(struct nl_msg *msg, struct nlattr *start, int keep_empty)
{
size_t pad, len;
- len = (void *) nlmsg_tail(msg->nm_nlh) - (void *) start;
+ len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) start;
- if (len == NLA_HDRLEN) {
+ if ( len > USHRT_MAX
+ || (!keep_empty && len == NLA_HDRLEN)) {
/*
- * Kernel can't handle empty nested attributes, trim the
+ * Max nlattr size exceeded or empty nested attribute, trim the
* attribute header again
*/
nla_nest_cancel(msg, start);
- return 0;
+ /* Return error only if nlattr size was exceeded */
+ return (len == NLA_HDRLEN) ? 0 : -NLE_ATTRSIZE;
}
start->nla_len = len;
@@ -854,6 +955,35 @@ int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
}
/**
+ * Finalize nesting of attributes.
+ * @arg msg Netlink message.
+ * @arg start Container attribute as returned from nla_nest_start().
+ *
+ * Corrects the container attribute header to include the appeneded attributes.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
+{
+ return _nest_end (msg, start, 0);
+}
+
+/**
+ * Finalize nesting of attributes without stripping off empty attributes.
+ * @arg msg Netlink message.
+ * @arg start Container attribute as returned from nla_nest_start().
+ *
+ * Corrects the container attribute header to include the appeneded attributes.
+ * Keep empty attribute if NO actual attribute payload exists.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nla_nest_end_keep_empty(struct nl_msg *msg, struct nlattr *start)
+{
+ return _nest_end (msg, start, 1);
+}
+
+/**
* Cancel the addition of a nested attribute
* @arg msg Netlink message
* @arg attr Nested netlink attribute
@@ -862,11 +992,11 @@ int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
* by resetting the message to the size before the call to nla_nest_start()
* and by overwriting any potentially touched message segments with 0.
*/
-void nla_nest_cancel(struct nl_msg *msg, struct nlattr *attr)
+void nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr)
{
ssize_t len;
- len = (void *) nlmsg_tail(msg->nm_nlh) - (void *) attr;
+ len = (char *) nlmsg_tail(msg->nm_nlh) - (char *) attr;
if (len < 0)
BUG();
else if (len > 0) {
@@ -889,7 +1019,7 @@ void nla_nest_cancel(struct nl_msg *msg, struct nlattr *attr)
* @return 0 on success or a negative error code.
*/
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
- struct nla_policy *policy)
+ const struct nla_policy *policy)
{
return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
}
@@ -900,7 +1030,7 @@ int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla,
*
* @return True if attribute has NLA_F_NESTED flag set, oterhwise False.
*/
-int nla_is_nested(struct nlattr *attr)
+int nla_is_nested(const struct nlattr *attr)
{
return !!(attr->nla_type & NLA_F_NESTED);
}
diff --git a/lib/cache.c b/lib/cache.c
index b4f9649c..4bb10d19 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/cache.c Caching Module
*
@@ -235,7 +236,7 @@ int nl_cache_alloc_and_fill(struct nl_cache_ops *ops, struct nl_sock *sock,
{
struct nl_cache *cache;
int err;
-
+
if (!(cache = nl_cache_alloc(ops)))
return -NLE_NOMEM;
@@ -421,7 +422,7 @@ void nl_cache_free(struct nl_cache *cache)
void nl_cache_put(struct nl_cache *cache)
{
- return nl_cache_free(cache);
+ nl_cache_free(cache);
}
/** @} */
@@ -527,7 +528,7 @@ int nl_cache_move(struct nl_cache *cache, struct nl_object *obj)
NL_DBG(3, "Moving object %p from cache %p to cache %p\n",
obj, obj->ce_cache, cache);
-
+
/* Acquire reference, if already in a cache this will be
* reverted during removal */
nl_object_get(obj);
@@ -589,7 +590,7 @@ void nl_cache_remove(struct nl_object *obj)
*/
void nl_cache_set_arg1(struct nl_cache *cache, int arg)
{
- cache->c_iarg1 = arg;
+ cache->c_iarg1 = arg;
}
/**
@@ -602,7 +603,7 @@ void nl_cache_set_arg1(struct nl_cache *cache, int arg)
*/
void nl_cache_set_arg2(struct nl_cache *cache, int arg)
{
- cache->c_iarg2 = arg;
+ cache->c_iarg2 = arg;
}
/**
@@ -637,7 +638,9 @@ void nl_cache_set_flags(struct nl_cache *cache, unsigned int flags)
*
* @see nl_cache_pickup(), nl_cache_resync()
*
- * @return 0 on success or a negative error code.
+ * @return 0 on success or a negative error code. Some implementations
+ * of co_request_update() return a positive number on success that is
+ * the number of bytes sent. Treat any non-negative number as success too.
*/
static int nl_cache_request_full_dump(struct nl_sock *sk,
struct nl_cache *cache)
@@ -708,7 +711,7 @@ static int __cache_pickup(struct nl_sock *sk, struct nl_cache *cache,
return err;
}
-static int pickup_cb(struct nl_object *c, struct nl_parser_param *p)
+static int pickup_checkdup_cb(struct nl_object *c, struct nl_parser_param *p)
{
struct nl_cache *cache = (struct nl_cache *)p->pp_arg;
struct nl_object *old;
@@ -727,6 +730,42 @@ static int pickup_cb(struct nl_object *c, struct nl_parser_param *p)
return nl_cache_add(cache, c);
}
+static int pickup_cb(struct nl_object *c, struct nl_parser_param *p)
+{
+ struct nl_cache *cache = p->pp_arg;
+
+ return nl_cache_add(cache, c);
+}
+
+static int __nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache,
+ int checkdup)
+{
+ struct nl_parser_param p;
+
+ p.pp_cb = checkdup ? pickup_checkdup_cb : pickup_cb;
+ p.pp_arg = cache;
+
+ if (sk->s_proto != cache->c_ops->co_protocol)
+ return -NLE_PROTO_MISMATCH;
+
+ return __cache_pickup(sk, cache, &p);
+}
+
+/**
+ * Pickup a netlink dump response and put it into a cache.
+ * @arg sk Netlink socket.
+ * @arg cache Cache to put items into.
+ *
+ * Waits for netlink messages to arrive, parses them and puts them into
+ * the specified cache.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_cache_pickup_checkdup(struct nl_sock *sk, struct nl_cache *cache)
+{
+ return __nl_cache_pickup(sk, cache, 1);
+}
+
/**
* Pickup a netlink dump response and put it into a cache.
* @arg sk Netlink socket.
@@ -742,42 +781,49 @@ static int pickup_cb(struct nl_object *c, struct nl_parser_param *p)
*/
int nl_cache_pickup(struct nl_sock *sk, struct nl_cache *cache)
{
- struct nl_parser_param p = {
- .pp_cb = pickup_cb,
- .pp_arg = cache,
- };
-
- if (sk->s_proto != cache->c_ops->co_protocol)
- return -NLE_PROTO_MISMATCH;
-
- return __cache_pickup(sk, cache, &p);
+ return __nl_cache_pickup(sk, cache, 0);
}
static int cache_include(struct nl_cache *cache, struct nl_object *obj,
- struct nl_msgtype *type, change_func_t cb, void *data)
+ struct nl_msgtype *type, change_func_t cb,
+ change_func_v2_t cb_v2, void *data)
{
struct nl_object *old;
+ struct nl_object *clone = NULL;
+ uint64_t diff = 0;
switch (type->mt_act) {
case NL_ACT_NEW:
case NL_ACT_DEL:
old = nl_cache_search(cache, obj);
if (old) {
+ if (cb_v2 && old->ce_ops->oo_update) {
+ clone = nl_object_clone(old);
+ diff = nl_object_diff64(old, obj);
+ }
/*
* Some objects types might support merging the new
* object with the old existing cache object.
* Handle them first.
*/
if (nl_object_update(old, obj) == 0) {
- if (cb)
+ if (cb_v2) {
+ cb_v2(cache, clone, obj, diff,
+ NL_ACT_CHANGE, data);
+ nl_object_put(clone);
+ } else if (cb)
cb(cache, old, NL_ACT_CHANGE, data);
nl_object_put(old);
return 0;
}
+ nl_object_put(clone);
nl_cache_remove(old);
if (type->mt_act == NL_ACT_DEL) {
- if (cb)
+ if (cb_v2)
+ cb_v2(cache, old, NULL, 0, NL_ACT_DEL,
+ data);
+ else if (cb)
cb(cache, old, NL_ACT_DEL, data);
nl_object_put(old);
}
@@ -785,10 +831,20 @@ static int cache_include(struct nl_cache *cache, struct nl_object *obj,
if (type->mt_act == NL_ACT_NEW) {
nl_cache_move(cache, obj);
- if (old == NULL && cb)
- cb(cache, obj, NL_ACT_NEW, data);
- else if (old) {
- if (nl_object_diff(old, obj) && cb)
+ if (old == NULL) {
+ if (cb_v2) {
+ cb_v2(cache, NULL, obj, 0, NL_ACT_NEW,
+ data);
+ } else if (cb)
+ cb(cache, obj, NL_ACT_NEW, data);
+ } else if (old) {
+ diff = 0;
+ if (cb || cb_v2)
+ diff = nl_object_diff64(old, obj);
+ if (diff && cb_v2) {
+ cb_v2(cache, old, obj, diff, NL_ACT_CHANGE,
+ data);
+ } else if (diff && cb)
cb(cache, obj, NL_ACT_CHANGE, data);
nl_object_put(old);
@@ -815,7 +871,27 @@ int nl_cache_include(struct nl_cache *cache, struct nl_object *obj,
for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype)
return cache_include(cache, obj, &ops->co_msgtypes[i],
- change_cb, data);
+ change_cb, NULL, data);
+
+ NL_DBG(3, "Object %p does not seem to belong to cache %p <%s>\n",
+ obj, cache, nl_cache_name(cache));
+
+ return -NLE_MSGTYPE_NOSUPPORT;
+}
+
+int nl_cache_include_v2(struct nl_cache *cache, struct nl_object *obj,
+ change_func_v2_t change_cb, void *data)
+{
+ struct nl_cache_ops *ops = cache->c_ops;
+ int i;
+
+ if (ops->co_obj_ops != obj->ce_ops)
+ return -NLE_OBJ_MISMATCH;
+
+ for (i = 0; ops->co_msgtypes[i].mt_id >= 0; i++)
+ if (ops->co_msgtypes[i].mt_id == obj->ce_msgtype)
+ return cache_include(cache, obj, &ops->co_msgtypes[i],
+ NULL, change_cb, data);
NL_DBG(3, "Object %p does not seem to belong to cache %p <%s>\n",
obj, cache, nl_cache_name(cache));
@@ -827,7 +903,12 @@ static int resync_cb(struct nl_object *c, struct nl_parser_param *p)
{
struct nl_cache_assoc *ca = p->pp_arg;
- return nl_cache_include(ca->ca_cache, c, ca->ca_change, ca->ca_change_data);
+ if (ca->ca_change_v2)
+ return nl_cache_include_v2(ca->ca_cache, c, ca->ca_change_v2,
+ ca->ca_change_data);
+ else
+ return nl_cache_include(ca->ca_cache, c, ca->ca_change,
+ ca->ca_change_data);
}
int nl_cache_resync(struct nl_sock *sk, struct nl_cache *cache,
@@ -1008,8 +1089,8 @@ static struct nl_object *__cache_fast_lookup(struct nl_cache *cache,
obj = nl_hash_table_lookup(cache->hashtable, needle);
if (obj) {
- nl_object_get(obj);
- return obj;
+ nl_object_get(obj);
+ return obj;
}
return NULL;
diff --git a/lib/cache_mngr.c b/lib/cache_mngr.c
index 9b25e9b8..380834f9 100644
--- a/lib/cache_mngr.c
+++ b/lib/cache_mngr.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/cache_mngr.c Cache Manager
*
@@ -33,6 +34,7 @@
*/
#include <netlink-private/netlink.h>
+#include <netlink-private/utils.h>
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/utils.h>
@@ -59,9 +61,15 @@ static int include_cb(struct nl_object *obj, struct nl_parser_param *p)
if (ops->co_include_event)
return ops->co_include_event(ca->ca_cache, obj, ca->ca_change,
+ ca->ca_change_v2,
ca->ca_change_data);
- else
- return nl_cache_include(ca->ca_cache, obj, ca->ca_change, ca->ca_change_data);
+ else {
+ if (ca->ca_change_v2)
+ return nl_cache_include_v2(ca->ca_cache, obj, ca->ca_change_v2, ca->ca_change_data);
+ else
+ return nl_cache_include(ca->ca_cache, obj, ca->ca_change, ca->ca_change_data);
+ }
+
}
static int event_input(struct nl_msg *msg, void *arg)
@@ -194,6 +202,70 @@ errout:
}
/**
+ * Set change_func_v2 for cache manager
+ * @arg mngr Cache manager.
+ * @arg cache Cache associated with the callback
+ * @arg cb Function to be called upon changes.
+ * @arg data Argument passed on to change callback
+ *
+ * Adds callback change_func_v2 to a registered cache. This callback provides
+ * in like the standard change_func the added or remove netlink object. In case
+ * of a change the old and the new object is provided as well as the according
+ * diff. If this callback is registered this has a higher priority then the
+ * change_func registered during cache registration. Hence only one callback is
+ * executed.
+ *
+ * The first netlink object in the callback is refering to the old object and
+ * the second to the new. This means on NL_ACT_CHANGE the first is the previous
+ * object in the cache and the second the updated version. On NL_ACT_DEL the
+ * first is the deleted object the second is NULL. On NL_ACT_NEW the first is
+ * NULL and the second the new netlink object.
+ *
+ * The user is responsible for calling nl_cache_mngr_poll() or monitor
+ * the socket and call nl_cache_mngr_data_ready() to allow the library
+ * to process netlink notification events.
+ *
+ * @see nl_cache_mngr_poll()
+ * @see nl_cache_mngr_data_ready()
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_PROTO_MISMATCH Protocol mismatch between cache manager and
+ * cache type
+ * @return -NLE_OPNOTSUPP Cache type does not support updates
+ * @return -NLE_RANGE Cache of this type is not registered
+ */
+static int nl_cache_mngr_set_change_func_v2(struct nl_cache_mngr *mngr,
+ struct nl_cache *cache,
+ change_func_v2_t cb, void *data)
+{
+ struct nl_cache_ops *ops;
+ int i;
+
+ ops = cache->c_ops;
+ if (!ops)
+ return -NLE_INVAL;
+
+ if (ops->co_protocol != mngr->cm_protocol)
+ return -NLE_PROTO_MISMATCH;
+
+ if (ops->co_groups == NULL)
+ return -NLE_OPNOTSUPP;
+
+ for (i = 0; i < mngr->cm_nassocs; i++)
+ if (mngr->cm_assocs[i].ca_cache == cache)
+ break;
+
+ if (i >= mngr->cm_nassocs) {
+ return -NLE_RANGE;
+ }
+
+ mngr->cm_assocs[i].ca_change_v2 = cb;
+ mngr->cm_assocs[i].ca_change_data = data;
+
+ return 0;
+}
+
+/**
* Add cache to cache manager
* @arg mngr Cache manager.
* @arg cache Cache to be added to cache manager
@@ -240,25 +312,26 @@ int nl_cache_mngr_add_cache(struct nl_cache_mngr *mngr, struct nl_cache *cache,
mngr->cm_assocs[i].ca_cache->c_ops == ops)
return -NLE_EXIST;
-retry:
for (i = 0; i < mngr->cm_nassocs; i++)
if (!mngr->cm_assocs[i].ca_cache)
break;
if (i >= mngr->cm_nassocs) {
- mngr->cm_nassocs += NASSOC_EXPAND;
- mngr->cm_assocs = realloc(mngr->cm_assocs,
- mngr->cm_nassocs *
- sizeof(struct nl_cache_assoc));
- if (mngr->cm_assocs == NULL)
+ struct nl_cache_assoc *cm_assocs;
+ int cm_nassocs = mngr->cm_nassocs + NASSOC_EXPAND;
+
+ cm_assocs = realloc(mngr->cm_assocs,
+ cm_nassocs * sizeof(struct nl_cache_assoc));
+ if (cm_assocs == NULL)
return -NLE_NOMEM;
- memset(mngr->cm_assocs + (mngr->cm_nassocs - NASSOC_EXPAND), 0,
+ memset(cm_assocs + mngr->cm_nassocs, 0,
NASSOC_EXPAND * sizeof(struct nl_cache_assoc));
+ mngr->cm_assocs = cm_assocs;
+ mngr->cm_nassocs = cm_nassocs;
NL_DBG(1, "Increased capacity of cache manager %p " \
"to %d\n", mngr, mngr->cm_nassocs);
- goto retry;
}
for (grp = ops->co_groups; grp->ag_group; grp++) {
@@ -293,6 +366,41 @@ errout_drop_membership:
/**
* Add cache to cache manager
* @arg mngr Cache manager.
+ * @arg cache Cache to be added to cache manager
+ * @arg cb V2 function to be called upon changes.
+ * @arg data Argument passed on to change callback
+ *
+ * Adds cache to the manager. The operation will trigger a full
+ * dump request from the kernel to initially fill the contents
+ * of the cache. The manager will subscribe to the notification group
+ * of the cache and keep track of any further changes.
+ *
+ * The user is responsible for calling nl_cache_mngr_poll() or monitor
+ * the socket and call nl_cache_mngr_data_ready() to allow the library
+ * to process netlink notification events.
+ *
+ * @see nl_cache_mngr_poll()
+ * @see nl_cache_mngr_data_ready()
+ *
+ * @return 0 on success or a negative error code.
+ * @return -NLE_PROTO_MISMATCH Protocol mismatch between cache manager and
+ * cache type
+ * @return -NLE_OPNOTSUPP Cache type does not support updates
+ * @return -NLE_EXIST Cache of this type already being managed
+ */
+int nl_cache_mngr_add_cache_v2(struct nl_cache_mngr *mngr, struct nl_cache *cache,
+ change_func_v2_t cb, void *data) {
+ int err;
+ err = nl_cache_mngr_add_cache(mngr, cache, NULL, NULL);
+ if (err < 0)
+ return err;
+
+ return nl_cache_mngr_set_change_func_v2(mngr, cache, cb, data);
+}
+
+/**
+ * Add cache to cache manager
+ * @arg mngr Cache manager.
* @arg name Name of cache to keep track of
* @arg cb Function to be called upon changes.
* @arg data Argument passed on to change callback
@@ -308,6 +416,9 @@ errout_drop_membership:
* the socket and call nl_cache_mngr_data_ready() to allow the library
* to process netlink notification events.
*
+ * @note Versions up to 3.4.0 actually required the result argument, preventing
+ * NULL to be passed.
+ *
* @see nl_cache_mngr_poll()
* @see nl_cache_mngr_data_ready()
*
@@ -338,7 +449,8 @@ int nl_cache_mngr_add(struct nl_cache_mngr *mngr, const char *name,
if (err < 0)
goto errout_free_cache;
- *result = cache;
+ if (result)
+ *result = cache;
return 0;
errout_free_cache:
@@ -391,8 +503,11 @@ int nl_cache_mngr_poll(struct nl_cache_mngr *mngr, int timeout)
NL_DBG(3, "Cache manager %p, poll() fd %d\n", mngr, fds.fd);
ret = poll(&fds, 1, timeout);
NL_DBG(3, "Cache manager %p, poll() returned %d\n", mngr, ret);
- if (ret < 0)
+ if (ret < 0) {
+ NL_DBG(4, "nl_cache_mngr_poll(%p): poll() failed with %d (%s)\n",
+ mngr, errno, nl_strerror_l(errno));
return -nl_syserr2nlerr(errno);
+ }
/* No events, return */
if (ret == 0)
diff --git a/lib/cache_mngt.c b/lib/cache_mngt.c
index 4d3d6ff6..4178e43d 100644
--- a/lib/cache_mngt.c
+++ b/lib/cache_mngt.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/cache_mngt.c Cache Management
*
@@ -38,7 +39,7 @@ static NL_RW_LOCK(cache_ops_lock);
* @{
*/
-struct nl_cache_ops *__nl_cache_ops_lookup(const char *name)
+static struct nl_cache_ops *__nl_cache_ops_lookup(const char *name)
{
struct nl_cache_ops *ops;
@@ -254,6 +255,9 @@ int nl_cache_mngt_register(struct nl_cache_ops *ops)
if (!ops->co_name || !ops->co_obj_ops)
return -NLE_INVAL;
+ /* oo_keygen() also needs oo_compare() */
+ BUG_ON (ops->co_obj_ops->oo_keygen && !ops->co_obj_ops->oo_compare);
+
nl_write_lock(&cache_ops_lock);
if (__nl_cache_ops_lookup(ops->co_name)) {
nl_write_unlock(&cache_ops_lock);
diff --git a/lib/cli/cls/basic.c b/lib/cli/cls/basic.c
index 1939988a..1a6b1887 100644
--- a/lib/cli/cls/basic.c
+++ b/lib/cli/cls/basic.c
@@ -49,7 +49,7 @@ static void parse_argv(struct rtnl_tc *tc, int argc, char **argv)
{ "ematch", 1, 0, 'e' },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "ht:e:", long_opts, &optidx);
if (c == -1)
break;
@@ -72,7 +72,7 @@ static void parse_argv(struct rtnl_tc *tc, int argc, char **argv)
rtnl_basic_set_ematch(cls, tree);
break;
}
- }
+ }
}
static struct nl_cli_tc_module basic_module =
diff --git a/lib/cli/cls/cgroup.c b/lib/cli/cls/cgroup.c
index fae62085..9e1443c2 100644
--- a/lib/cli/cls/cgroup.c
+++ b/lib/cli/cls/cgroup.c
@@ -39,7 +39,7 @@ static void parse_argv(struct rtnl_tc *tc, int argc, char **argv)
{ "ematch", 1, 0, 'e' },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "he:", long_opts, &optidx);
if (c == -1)
break;
@@ -54,7 +54,7 @@ static void parse_argv(struct rtnl_tc *tc, int argc, char **argv)
rtnl_cgroup_set_ematch(cls, tree);
break;
}
- }
+ }
}
static struct nl_cli_tc_module cgroup_module =
diff --git a/lib/cli/qdisc/bfifo.c b/lib/cli/qdisc/bfifo.c
index 1ee47773..6b0206f2 100644
--- a/lib/cli/qdisc/bfifo.c
+++ b/lib/cli/qdisc/bfifo.c
@@ -42,7 +42,7 @@ static void bfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
{ "limit", 1, 0, ARG_LIMIT },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "h", long_opts, &optidx);
if (c == -1)
break;
@@ -62,7 +62,7 @@ static void bfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
rtnl_qdisc_fifo_set_limit(qdisc, limit);
break;
}
- }
+ }
}
static struct nl_cli_tc_module bfifo_module =
diff --git a/lib/cli/qdisc/blackhole.c b/lib/cli/qdisc/blackhole.c
index af9dc6d8..372855f8 100644
--- a/lib/cli/qdisc/blackhole.c
+++ b/lib/cli/qdisc/blackhole.c
@@ -33,7 +33,7 @@ static void blackhole_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
{ "help", 0, 0, 'h' },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "h", long_opts, &optidx);
if (c == -1)
break;
@@ -43,7 +43,7 @@ static void blackhole_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
print_usage();
return;
}
- }
+ }
}
static struct nl_cli_tc_module blackhole_module =
diff --git a/lib/cli/qdisc/fq_codel.c b/lib/cli/qdisc/fq_codel.c
index 1602bcba..a592f903 100644
--- a/lib/cli/qdisc/fq_codel.c
+++ b/lib/cli/qdisc/fq_codel.c
@@ -55,7 +55,7 @@ static void fq_codel_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
{ "target", 1, 0, ARG_TARGET},
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "h", long_opts, &optidx);
if (c == -1)
break;
@@ -91,7 +91,7 @@ static void fq_codel_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
break;
}
- }
+ }
}
static struct nl_cli_tc_module fq_codel_module =
diff --git a/lib/cli/qdisc/hfsc.c b/lib/cli/qdisc/hfsc.c
new file mode 100644
index 00000000..619befcf
--- /dev/null
+++ b/lib/cli/qdisc/hfsc.c
@@ -0,0 +1,252 @@
+/*
+ * lib/cli/qdisc/hfsc.c HFSC module for CLI lib
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2014 Cong Wang <xiyou.wangcong@gmail.com>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/tc.h>
+#include <netlink/route/qdisc/hfsc.h>
+#include <linux/pkt_sched.h>
+
+static void print_qdisc_usage(void)
+{
+ printf(
+"Usage: nl-qdisc-add [...] hfsc [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+" --help Show this help text.\n"
+" --default=ID Default class for unclassified traffic.\n"
+"\n"
+"EXAMPLE"
+" # Create hfsc root qdisc 1: and direct unclassified traffic to class 1:10\n"
+" nl-qdisc-add --dev=eth1 --parent=root --handle=1: hfsc --default=10\n");
+}
+
+static void hfsc_parse_qdisc_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+ struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
+
+ for (;;) {
+ int c, optidx = 0;
+ enum {
+ ARG_DEFAULT = 257,
+ };
+ static struct option long_opts[] = {
+ { "help", 0, 0, 'h' },
+ { "default", 1, 0, ARG_DEFAULT },
+ { 0, 0, 0, 0 }
+ };
+
+ c = getopt_long(argc, argv, "hv", long_opts, &optidx);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_qdisc_usage();
+ return;
+
+ case ARG_DEFAULT:
+ rtnl_qdisc_hfsc_set_defcls(qdisc, nl_cli_parse_u32(optarg));
+ break;
+ }
+ }
+}
+
+static void print_class_usage(void)
+{
+ printf(
+"Usage: nl-class-add [...] hfsc [OPTIONS]...\n"
+"\n"
+"OPTIONS\n"
+" --help Show this help text.\n"
+" --ls=SC Link-sharing service curve\n"
+" --rt=SC Real-time service curve\n"
+" --sc=SC Specifiy both of the above\n"
+" --ul=SC Upper limit\n"
+" where SC := [ [ m1 bits ] d usec ] m2 bits\n"
+"\n"
+"EXAMPLE"
+" # Attach class 1:1 to hfsc qdisc 1: and use rt and ls curve\n"
+" nl-class-add --dev=eth1 --parent=1: --classid=1:1 hfsc --sc=m1:250,d:8,m2:100\n");
+}
+
+static int
+hfsc_get_sc(char *optarg, struct tc_service_curve *sc)
+{
+ unsigned int m1 = 0, d = 0, m2 = 0;
+ char *tmp = strdup(optarg);
+ char *p, *endptr;
+ char *pp = tmp;
+
+ if (!tmp)
+ return -ENOMEM;
+
+ p = strstr(pp, "m1:");
+ if (p) {
+ char *q;
+ p += 3;
+ if (*p == 0)
+ goto err;
+ q = strchr(p, ',');
+ if (!q)
+ goto err;
+ *q = 0;
+ m1 = strtoul(p, &endptr, 10);
+ if (endptr == p)
+ goto err;
+ pp = q + 1;
+ }
+
+ p = strstr(pp, "d:");
+ if (p) {
+ char *q;
+ p += 2;
+ if (*p == 0)
+ goto err;
+ q = strchr(p, ',');
+ if (!q)
+ goto err;
+ *q = 0;
+ d = strtoul(p, &endptr, 10);
+ if (endptr == p)
+ goto err;
+ pp = q + 1;
+ }
+
+ p = strstr(pp, "m2:");
+ if (p) {
+ p += 3;
+ if (*p == 0)
+ goto err;
+ m2 = strtoul(p, &endptr, 10);
+ if (endptr == p)
+ goto err;
+ } else
+ goto err;
+
+ free(tmp);
+ sc->m1 = m1;
+ sc->d = d;
+ sc->m2 = m2;
+ return 0;
+
+err:
+ free(tmp);
+ return -EINVAL;
+}
+
+static void hfsc_parse_class_argv(struct rtnl_tc *tc, int argc, char **argv)
+{
+ struct rtnl_class *class = (struct rtnl_class *) tc;
+ int arg_ok = 0, ret = -EINVAL;
+
+ for (;;) {
+ int c, optidx = 0;
+ enum {
+ ARG_RT = 257,
+ ARG_LS = 258,
+ ARG_SC,
+ ARG_UL,
+ };
+ static struct option long_opts[] = {
+ { "help", 0, 0, 'h' },
+ { "rt", 1, 0, ARG_RT },
+ { "ls", 1, 0, ARG_LS },
+ { "sc", 1, 0, ARG_SC },
+ { "ul", 1, 0, ARG_UL },
+ { 0, 0, 0, 0 }
+ };
+ struct tc_service_curve tsc;
+
+ c = getopt_long(argc, argv, "h", long_opts, &optidx);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_class_usage();
+ return;
+
+ case ARG_RT:
+ ret = hfsc_get_sc(optarg, &tsc);
+ if (ret < 0) {
+ nl_cli_fatal(ret, "Unable to parse sc "
+ "\"%s\": Invalid format.", optarg);
+ }
+
+ rtnl_class_hfsc_set_rsc(class, &tsc);
+ arg_ok++;
+ break;
+
+ case ARG_LS:
+ ret = hfsc_get_sc(optarg, &tsc);
+ if (ret < 0) {
+ nl_cli_fatal(ret, "Unable to parse sc "
+ "\"%s\": Invalid format.", optarg);
+ }
+
+ rtnl_class_hfsc_set_fsc(class, &tsc);
+ arg_ok++;
+ break;
+
+ case ARG_SC:
+ ret = hfsc_get_sc(optarg, &tsc);
+ if (ret < 0) {
+ nl_cli_fatal(ret, "Unable to parse sc "
+ "\"%s\": Invalid format.", optarg);
+ }
+
+ rtnl_class_hfsc_set_rsc(class, &tsc);
+ rtnl_class_hfsc_set_fsc(class, &tsc);
+ arg_ok++;
+ break;
+
+ case ARG_UL:
+ ret = hfsc_get_sc(optarg, &tsc);
+ if (ret < 0) {
+ nl_cli_fatal(ret, "Unable to parse sc "
+ "\"%s\": Invalid format.", optarg);
+ }
+
+ rtnl_class_hfsc_set_usc(class, &tsc);
+ arg_ok++;
+ break;
+ }
+ }
+
+ if (!arg_ok)
+ nl_cli_fatal(ret, "Invalid arguments");
+}
+
+static struct nl_cli_tc_module hfsc_qdisc_module =
+{
+ .tm_name = "hfsc",
+ .tm_type = RTNL_TC_TYPE_QDISC,
+ .tm_parse_argv = hfsc_parse_qdisc_argv,
+};
+
+static struct nl_cli_tc_module hfsc_class_module =
+{
+ .tm_name = "hfsc",
+ .tm_type = RTNL_TC_TYPE_CLASS,
+ .tm_parse_argv = hfsc_parse_class_argv,
+};
+
+static void __init hfsc_init(void)
+{
+ nl_cli_tc_register(&hfsc_qdisc_module);
+ nl_cli_tc_register(&hfsc_class_module);
+}
+
+static void __exit hfsc_exit(void)
+{
+ nl_cli_tc_unregister(&hfsc_class_module);
+ nl_cli_tc_unregister(&hfsc_qdisc_module);
+}
diff --git a/lib/cli/qdisc/htb.c b/lib/cli/qdisc/htb.c
index 1751595e..628e6ccb 100644
--- a/lib/cli/qdisc/htb.c
+++ b/lib/cli/qdisc/htb.c
@@ -44,7 +44,7 @@ static void htb_parse_qdisc_argv(struct rtnl_tc *tc, int argc, char **argv)
{ "default", 1, 0, ARG_DEFAULT },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "hv", long_opts, &optidx);
if (c == -1)
break;
@@ -62,7 +62,7 @@ static void htb_parse_qdisc_argv(struct rtnl_tc *tc, int argc, char **argv)
rtnl_htb_set_defcls(qdisc, nl_cli_parse_u32(optarg));
break;
}
- }
+ }
}
static void print_class_usage(void)
@@ -109,7 +109,7 @@ static void htb_parse_class_argv(struct rtnl_tc *tc, int argc, char **argv)
{ "cburst", 1, 0, ARG_CBURST },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "h", long_opts, &optidx);
if (c == -1)
break;
@@ -173,7 +173,7 @@ static void htb_parse_class_argv(struct rtnl_tc *tc, int argc, char **argv)
rtnl_htb_set_cbuffer(class, rate);
break;
}
- }
+ }
}
static struct nl_cli_tc_module htb_qdisc_module =
diff --git a/lib/cli/qdisc/pfifo.c b/lib/cli/qdisc/pfifo.c
index 02c4d229..7aac7df9 100644
--- a/lib/cli/qdisc/pfifo.c
+++ b/lib/cli/qdisc/pfifo.c
@@ -42,7 +42,7 @@ static void pfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
{ "limit", 1, 0, ARG_LIMIT },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "h", long_opts, &optidx);
if (c == -1)
break;
@@ -56,7 +56,7 @@ static void pfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
rtnl_qdisc_fifo_set_limit(qdisc, nl_cli_parse_u32(optarg));
break;
}
- }
+ }
}
static struct nl_cli_tc_module pfifo_module =
diff --git a/lib/cli/qdisc/plug.c b/lib/cli/qdisc/plug.c
index 2b8d5d65..227082d4 100644
--- a/lib/cli/qdisc/plug.c
+++ b/lib/cli/qdisc/plug.c
@@ -66,7 +66,7 @@ static void plug_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
{ "release-indefinite", 0, 0, ARG_RELEASE_INDEFINITE },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "h", long_opts, &optidx);
if (c == -1)
break;
@@ -85,14 +85,14 @@ static void plug_parse_argv(struct rtnl_tc *tc, int argc, char **argv)
break;
case ARG_RELEASE_ONE:
- rtnl_qdisc_plug_release_one(qdisc);
+ rtnl_qdisc_plug_release_one(qdisc);
break;
case ARG_RELEASE_INDEFINITE:
rtnl_qdisc_plug_release_indefinite(qdisc);
break;
}
- }
+ }
}
static struct nl_cli_tc_module plug_module =
diff --git a/lib/data.c b/lib/data.c
index 1a3a3fbd..fea3060e 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/data.c Abstract Data
*
@@ -47,7 +48,7 @@
*
* @return Newly allocated data handle or NULL
*/
-struct nl_data *nl_data_alloc(void *buf, size_t size)
+struct nl_data *nl_data_alloc(const void *buf, size_t size)
{
struct nl_data *data;
@@ -81,7 +82,7 @@ errout:
* @see nla_data_alloc
* @return Newly allocated data handle or NULL
*/
-struct nl_data *nl_data_alloc_attr(struct nlattr *nla)
+struct nl_data *nl_data_alloc_attr(const struct nlattr *nla)
{
return nl_data_alloc(nla_data(nla), nla_len(nla));
}
@@ -92,7 +93,7 @@ struct nl_data *nl_data_alloc_attr(struct nlattr *nla)
*
* @return Cloned object or NULL
*/
-struct nl_data *nl_data_clone(struct nl_data *src)
+struct nl_data *nl_data_clone(const struct nl_data *src)
{
return nl_data_alloc(src->d_data, src->d_size);
}
@@ -108,18 +109,19 @@ struct nl_data *nl_data_clone(struct nl_data *src)
*
* @return 0 on success or a negative error code
*/
-int nl_data_append(struct nl_data *data, void *buf, size_t size)
+int nl_data_append(struct nl_data *data, const void *buf, size_t size)
{
if (size > 0) {
- data->d_data = realloc(data->d_data, data->d_size + size);
- if (!data->d_data)
+ char *d_data = realloc(data->d_data, data->d_size + size);
+ if (!d_data)
return -NLE_NOMEM;
if (buf)
- memcpy(data->d_data + data->d_size, buf, size);
+ memcpy(d_data + data->d_size, buf, size);
else
- memset(data->d_data + data->d_size, 0, size);
+ memset(d_data + data->d_size, 0, size);
+ data->d_data = d_data;
data->d_size += size;
}
@@ -150,9 +152,11 @@ void nl_data_free(struct nl_data *data)
* @arg data Abstract data object.
* @return Data buffer or NULL if empty.
*/
-void *nl_data_get(struct nl_data *data)
+void *nl_data_get(const struct nl_data *data)
{
- return data->d_size > 0 ? data->d_data : NULL;
+ if (data->d_size > 0)
+ return (void*)data->d_data;
+ return NULL;
}
/**
@@ -160,7 +164,7 @@ void *nl_data_get(struct nl_data *data)
* @arg data Abstract data object.
* @return Size of data buffer.
*/
-size_t nl_data_get_size(struct nl_data *data)
+size_t nl_data_get_size(const struct nl_data *data)
{
return data->d_size;
}
@@ -180,10 +184,10 @@ size_t nl_data_get_size(struct nl_data *data)
* a is found, respectively, to be less than, to match, or
* be greater than b.
*/
-int nl_data_cmp(struct nl_data *a, struct nl_data *b)
+int nl_data_cmp(const struct nl_data *a, const struct nl_data *b)
{
- void *a_ = nl_data_get(a);
- void *b_ = nl_data_get(b);
+ const void *a_ = nl_data_get(a);
+ const void *b_ = nl_data_get(b);
if (a_ && b_)
return memcmp(a_, b_, nl_data_get_size(a));
diff --git a/lib/error.c b/lib/error.c
index f30b9a59..1106cb0a 100644
--- a/lib/error.c
+++ b/lib/error.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/error.c Error Handling
*
@@ -47,6 +48,7 @@ static const char *errmsg[NLE_MAX+1] = {
[NLE_NODEV] = "No such device",
[NLE_IMMUTABLE] = "Immutable attribute",
[NLE_DUMP_INTR] = "Dump inconsistency detected, interrupted",
+[NLE_ATTRSIZE] = "Attribute max length exceeded",
};
/**
diff --git a/lib/fib_lookup/lookup.c b/lib/fib_lookup/lookup.c
index 3d073172..fbd62917 100644
--- a/lib/fib_lookup/lookup.c
+++ b/lib/fib_lookup/lookup.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/fib_lookup/lookup.c FIB Lookup
*
@@ -17,6 +18,7 @@
*/
#include <netlink-private/netlink.h>
+#include <netlink-private/utils.h>
#include <netlink/netlink.h>
#include <netlink/attr.h>
#include <netlink/utils.h>
@@ -133,7 +135,7 @@ static void result_dump_line(struct nl_object *obj, struct nl_dump_params *p)
nl_rtntype2str(res->fr_type, buf, sizeof(buf)));
nl_dump(p, "scope %s error %s (%d)\n",
rtnl_scope2str(res->fr_scope, buf, sizeof(buf)),
- strerror_r(-res->fr_error, buf, sizeof(buf)), res->fr_error);
+ nl_strerror_l(-res->fr_error), res->fr_error);
}
static void result_dump_details(struct nl_object *obj, struct nl_dump_params *p)
@@ -141,8 +143,8 @@ static void result_dump_details(struct nl_object *obj, struct nl_dump_params *p)
result_dump_line(obj, p);
}
-static int result_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint64_t result_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
return 0;
}
@@ -270,7 +272,7 @@ int flnl_lookup(struct nl_sock *sk, struct flnl_request *req,
if (err < 0)
return err;
- return nl_cache_pickup(sk, cache);
+ return nl_cache_pickup_checkdup(sk, cache);
}
/** @} */
diff --git a/lib/fib_lookup/request.c b/lib/fib_lookup/request.c
index 1b021b64..7749a070 100644
--- a/lib/fib_lookup/request.c
+++ b/lib/fib_lookup/request.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/fib_lookup/request.c FIB Lookup Request
*
@@ -53,12 +54,12 @@ static int request_clone(struct nl_object *_dst, struct nl_object *_src)
return 0;
}
-static int request_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint64_t request_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct flnl_request *a = (struct flnl_request *) _a;
struct flnl_request *b = (struct flnl_request *) _b;
- int diff = 0;
+ uint64_t diff = 0;
#define REQ_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, REQUEST_ATTR_##ATTR, a, b, EXPR)
diff --git a/lib/genl/ctrl.c b/lib/genl/ctrl.c
index ce07f1d4..2d5d6f2a 100644
--- a/lib/genl/ctrl.c
+++ b/lib/genl/ctrl.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/genl/ctrl.c Generic Netlink Controller
*
diff --git a/lib/genl/family.c b/lib/genl/family.c
index 897c809e..ed8b08b8 100644
--- a/lib/genl/family.c
+++ b/lib/genl/family.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/genl/family.c Generic Netlink Family
*
@@ -24,6 +25,8 @@
#include <netlink/genl/family.h>
#include <netlink/utils.h>
+#include "netlink-private/utils.h"
+
/** @cond SKIP */
#define FAMILY_ATTR_ID 0x01
#define FAMILY_ATTR_NAME 0x02
@@ -96,10 +99,10 @@ static void family_dump_line(struct nl_object *obj, struct nl_dump_params *p)
}
static const struct trans_tbl ops_flags[] = {
- __ADD(GENL_ADMIN_PERM, admin_perm)
- __ADD(GENL_CMD_CAP_DO, has_doit)
- __ADD(GENL_CMD_CAP_DUMP, has_dump)
- __ADD(GENL_CMD_CAP_HASPOL, has_policy)
+ __ADD(GENL_ADMIN_PERM, admin_perm),
+ __ADD(GENL_CMD_CAP_DO, has_doit),
+ __ADD(GENL_CMD_CAP_DUMP, has_dump),
+ __ADD(GENL_CMD_CAP_HASPOL, has_policy),
};
static char *ops_flags2str(int flags, char *buf, size_t len)
@@ -147,12 +150,12 @@ static void family_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
family_dump_details(obj, p);
}
-static int family_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint64_t family_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct genl_family *a = (struct genl_family *) _a;
struct genl_family *b = (struct genl_family *) _b;
- int diff = 0;
+ uint64_t diff = 0;
#define FAM_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, FAMILY_ATTR_##ATTR, a, b, EXPR)
@@ -215,7 +218,7 @@ unsigned int genl_family_get_id(struct genl_family *family)
if (family->ce_mask & FAMILY_ATTR_ID)
return family->gf_id;
else
- return GENL_ID_GENERATE;
+ return 0;
}
/**
@@ -330,7 +333,7 @@ uint32_t genl_family_get_maxattr(struct genl_family *family)
if (family->ce_mask & FAMILY_ATTR_MAXATTR)
return family->gf_maxattr;
else
- return family->gf_maxattr;
+ return 0;
}
void genl_family_set_maxattr(struct genl_family *family, uint32_t maxattr)
@@ -364,16 +367,20 @@ int genl_family_add_op(struct genl_family *family, int id, int flags)
}
int genl_family_add_grp(struct genl_family *family, uint32_t id,
- const char *name)
+ const char *name)
{
- struct genl_family_grp *grp;
+ struct genl_family_grp *grp;
+
+ if ( !name
+ || strlen (name) >= GENL_NAMSIZ)
+ return -NLE_INVAL;
grp = calloc(1, sizeof(*grp));
if (grp == NULL)
return -NLE_NOMEM;
grp->id = id;
- strncpy(grp->name, name, GENL_NAMSIZ - 1);
+ _nl_strncpy(grp->name, name, GENL_NAMSIZ);
nl_list_add_tail(&grp->list, &family->gf_mc_grps);
diff --git a/lib/genl/genl.c b/lib/genl/genl.c
index 0c9b11eb..b4f37b5b 100644
--- a/lib/genl/genl.c
+++ b/lib/genl/genl.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/genl/genl.c Generic Netlink
*
@@ -79,7 +80,8 @@ int genl_connect(struct nl_sock *sk)
*
* @see nl_send_simple()
*
- * @return 0 on success or a negative error code.
+ * @return 0 on success or a negative error code. Due to a bug, this function
+ * returns the number of bytes sent. Treat any non-negative number as success.
*/
int genl_send_simple(struct nl_sock *sk, int family, int cmd,
int version, int flags)
@@ -149,7 +151,7 @@ int genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
* @return 0 on success or a negative error code.
*/
int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
- struct nla_policy *policy)
+ const struct nla_policy *policy)
{
struct genlmsghdr *ghdr;
@@ -177,7 +179,7 @@ int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
* @code
* struct nlattr *attrs[MY_TYPE_MAX+1];
*
- * if ((err = genlsmg_parse(nlmsg_nlh(msg), sizeof(struct my_hdr), attrs,
+ * if ((err = genlmsg_parse(nlmsg_hdr(msg), sizeof(struct my_hdr), attrs,
* MY_TYPE_MAX, attr_policy)) < 0)
* // ERROR
* @endcode
@@ -189,7 +191,7 @@ int genlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
* @return 0 on success or a negative error code.
*/
int genlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
- int maxtype, struct nla_policy *policy)
+ int maxtype, const struct nla_policy *policy)
{
struct genlmsghdr *ghdr;
@@ -258,7 +260,7 @@ void *genlmsg_user_hdr(const struct genlmsghdr *gnlh)
*/
void *genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen)
{
- return genlmsg_user_hdr(gnlh) + NLMSG_ALIGN(hdrlen);
+ return (char *) genlmsg_user_hdr(gnlh) + NLMSG_ALIGN(hdrlen);
}
/**
@@ -362,7 +364,7 @@ void *genlmsg_put(struct nl_msg *msg, uint32_t port, uint32_t seq, int family,
NL_DBG(2, "msg %p: Added generic netlink header cmd=%d version=%d\n",
msg, cmd, version);
- return nlmsg_data(nlh) + GENL_HDRLEN;
+ return (char *) nlmsg_data(nlh) + GENL_HDRLEN;
}
/** @} */
diff --git a/lib/genl/mngt.c b/lib/genl/mngt.c
index 36486636..28326cdb 100644
--- a/lib/genl/mngt.c
+++ b/lib/genl/mngt.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/genl/mngt.c Generic Netlink Management
*
@@ -26,6 +27,8 @@
#include <netlink/genl/ctrl.h>
#include <netlink/utils.h>
+#include "netlink-private/utils.h"
+
/** @cond SKIP */
static NL_LIST_HEAD(genl_ops_list);
@@ -45,41 +48,45 @@ static struct genl_cmd *lookup_cmd(struct genl_ops *ops, int cmd_id)
}
static int cmd_msg_parser(struct sockaddr_nl *who, struct nlmsghdr *nlh,
- struct genl_ops *ops, struct nl_cache_ops *cache_ops, void *arg)
+ struct genl_ops *ops, struct nl_cache_ops *cache_ops, void *arg)
{
+ _nl_auto_free struct nlattr **tb_free = NULL;
int err;
struct genlmsghdr *ghdr;
struct genl_cmd *cmd;
+ struct nlattr **tb;
ghdr = genlmsg_hdr(nlh);
- if (!(cmd = lookup_cmd(ops, ghdr->cmd))) {
- err = -NLE_MSGTYPE_NOSUPPORT;
- goto errout;
- }
+ if (!(cmd = lookup_cmd(ops, ghdr->cmd)))
+ return -NLE_MSGTYPE_NOSUPPORT;
if (cmd->c_msg_parser == NULL)
- err = -NLE_OPNOTSUPP;
- else {
- struct nlattr *tb[cmd->c_maxattr + 1];
+ return -NLE_OPNOTSUPP;
+
+ tb = _nl_malloc_maybe_a (300, (((size_t) cmd->c_maxattr) + 1u) * sizeof (struct nlattr *), &tb_free);
+ if (!tb)
+ return -NLE_NOMEM;
+
+ err = nlmsg_parse(nlh,
+ GENL_HDRSIZE(ops->o_hdrsize),
+ tb,
+ cmd->c_maxattr,
+ cmd->c_attr_policy);
+ if (err < 0)
+ return err;
+
+ {
struct genl_info info = {
- .who = who,
- .nlh = nlh,
+ .who = who,
+ .nlh = nlh,
.genlhdr = ghdr,
.userhdr = genlmsg_user_hdr(ghdr),
- .attrs = tb,
+ .attrs = tb,
};
- err = nlmsg_parse(nlh, GENL_HDRSIZE(ops->o_hdrsize), tb, cmd->c_maxattr,
- cmd->c_attr_policy);
- if (err < 0)
- goto errout;
-
- err = cmd->c_msg_parser(cache_ops, cmd, &info, arg);
+ return cmd->c_msg_parser(cache_ops, cmd, &info, arg);
}
-errout:
- return err;
-
}
static int genl_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
@@ -313,7 +320,7 @@ int genl_resolve_id(struct genl_ops *ops)
int err = 0;
/* Check if resolved already */
- if (ops->o_id != GENL_ID_GENERATE)
+ if (ops->o_id != 0)
return 0;
if (!ops->o_name)
diff --git a/lib/handlers.c b/lib/handlers.c
index a6a97bb8..85cb3c63 100644
--- a/lib/handlers.c
+++ b/lib/handlers.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/handlers.c default netlink message handlers
*
@@ -26,6 +27,7 @@
*/
#include <netlink-private/netlink.h>
+#include <netlink-private/utils.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/msg.h>
@@ -79,10 +81,9 @@ static int nl_error_handler_verbose(struct sockaddr_nl *who,
struct nlmsgerr *e, void *arg)
{
FILE *ofd = arg ? arg : stderr;
- char buf[256];
fprintf(ofd, "-- Error received: %s\n-- Original message: ",
- strerror_r(-e->error, buf, sizeof(buf)));
+ nl_strerror_l(-e->error));
print_header_content(ofd, &e->msg);
fprintf(ofd, "\n");
@@ -203,7 +204,7 @@ struct nl_cb *nl_cb_alloc(enum nl_cb_kind kind)
int i;
struct nl_cb *cb;
- if (kind < 0 || kind > NL_CB_KIND_MAX)
+ if ((unsigned int) kind > NL_CB_KIND_MAX)
return NULL;
cb = calloc(1, sizeof(*cb));
@@ -293,10 +294,10 @@ enum nl_cb_type nl_cb_active_type(struct nl_cb *cb)
int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind,
nl_recvmsg_msg_cb_t func, void *arg)
{
- if (type < 0 || type > NL_CB_TYPE_MAX)
+ if ((unsigned int) type > NL_CB_TYPE_MAX)
return -NLE_RANGE;
- if (kind < 0 || kind > NL_CB_KIND_MAX)
+ if ((unsigned int) kind > NL_CB_KIND_MAX)
return -NLE_RANGE;
if (kind == NL_CB_CUSTOM) {
@@ -343,7 +344,7 @@ int nl_cb_set_all(struct nl_cb *cb, enum nl_cb_kind kind,
int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind,
nl_recvmsg_err_cb_t func, void *arg)
{
- if (kind < 0 || kind > NL_CB_KIND_MAX)
+ if ((unsigned int) kind > NL_CB_KIND_MAX)
return -NLE_RANGE;
if (kind == NL_CB_CUSTOM) {
diff --git a/lib/hash.c b/lib/hash.c
index 47c938b9..17b5c8f2 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* This code was taken from http://ccodearchive.net/info/hash.html
* The original file was modified to remove unwanted code
@@ -321,17 +322,17 @@ static uint32_t hashlittle( const void *key, size_t length, uint32_t *val2 )
/*-------------------------------- last block: affect all 32 bits of (c) */
switch(length) /* all the case statements fall through */
{
- case 12: c+=((uint32_t)k[11])<<24;
- case 11: c+=((uint32_t)k[10])<<16;
- case 10: c+=((uint32_t)k[9])<<8;
- case 9 : c+=k[8];
- case 8 : b+=((uint32_t)k[7])<<24;
- case 7 : b+=((uint32_t)k[6])<<16;
- case 6 : b+=((uint32_t)k[5])<<8;
- case 5 : b+=k[4];
- case 4 : a+=((uint32_t)k[3])<<24;
- case 3 : a+=((uint32_t)k[2])<<16;
- case 2 : a+=((uint32_t)k[1])<<8;
+ case 12: c+=((uint32_t)k[11])<<24; /* fall through */
+ case 11: c+=((uint32_t)k[10])<<16; /* fall through */
+ case 10: c+=((uint32_t)k[9])<<8; /* fall through */
+ case 9 : c+=k[8]; /* fall through */
+ case 8 : b+=((uint32_t)k[7])<<24; /* fall through */
+ case 7 : b+=((uint32_t)k[6])<<16; /* fall through */
+ case 6 : b+=((uint32_t)k[5])<<8; /* fall through */
+ case 5 : b+=k[4]; /* fall through */
+ case 4 : a+=((uint32_t)k[3])<<24; /* fall through */
+ case 3 : a+=((uint32_t)k[2])<<16; /* fall through */
+ case 2 : a+=((uint32_t)k[1])<<8; /* fall through */
case 1 : a+=k[0];
break;
case 0 : return c;
@@ -451,18 +452,18 @@ static uint32_t hashbig( const void *key, size_t length, uint32_t *val2)
/*-------------------------------- last block: affect all 32 bits of (c) */
switch(length) /* all the case statements fall through */
{
- case 12: c+=k[11];
- case 11: c+=((uint32_t)k[10])<<8;
- case 10: c+=((uint32_t)k[9])<<16;
- case 9 : c+=((uint32_t)k[8])<<24;
- case 8 : b+=k[7];
- case 7 : b+=((uint32_t)k[6])<<8;
- case 6 : b+=((uint32_t)k[5])<<16;
- case 5 : b+=((uint32_t)k[4])<<24;
- case 4 : a+=k[3];
- case 3 : a+=((uint32_t)k[2])<<8;
- case 2 : a+=((uint32_t)k[1])<<16;
- case 1 : a+=((uint32_t)k[0])<<24;
+ case 12: c+=k[11]; /* fall through */
+ case 11: c+=((uint32_t)k[10])<<8; /* fall through */
+ case 10: c+=((uint32_t)k[9])<<16; /* fall through */
+ case 9 : c+=((uint32_t)k[8])<<24; /* fall through */
+ case 8 : b+=k[7]; /* fall through */
+ case 7 : b+=((uint32_t)k[6])<<8; /* fall through */
+ case 6 : b+=((uint32_t)k[5])<<16; /* fall through */
+ case 5 : b+=((uint32_t)k[4])<<24; /* fall through */
+ case 4 : a+=k[3]; /* fall through */
+ case 3 : a+=((uint32_t)k[2])<<8; /* fall through */
+ case 2 : a+=((uint32_t)k[1])<<16; /* fall through */
+ case 1 : a+=((uint32_t)k[0])<<24; /* fall through */
break;
case 0 : return c;
}
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 8b159251..db4ed8b6 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* netlink/hashtable.c Netlink hashtable Utilities
*
@@ -191,7 +192,7 @@ int nl_hash_table_del(nl_hash_table_t *ht, struct nl_object *obj)
uint32_t nl_hash(void *k, size_t length, uint32_t initval)
{
- return(__nl_hash(k, length, initval));
+ return(__nl_hash((char *) k, length, initval));
}
/** @} */
diff --git a/lib/idiag/idiag.c b/lib/idiag/idiag.c
index 81d73db1..23a8413a 100644
--- a/lib/idiag/idiag.c
+++ b/lib/idiag/idiag.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/idiag/idiag.c Inet Diag Netlink
*
@@ -55,9 +56,11 @@ int idiagnl_connect(struct nl_sock *sk)
* @arg flags Message flags
* @arg family Address family
* @arg states Socket states to query
- * @arg ext Inet Diag attribute extensions to query
+ * @arg ext Inet Diag attribute extensions to query. Note that this only supports
+ * 8 bit arguments. Flags outside uint8_t range are silently ignored.
*
- * @return Newly allocated netlink message or NULL.
+ * @return 0 on success or a negative error code. Due to a bug, this function
+ * returns the number of bytes sent. Treat any non-negative number as success.
*/
int idiagnl_send_simple(struct nl_sock *sk, int flags, uint8_t family,
uint16_t states, uint16_t ext)
@@ -82,25 +85,22 @@ int idiagnl_send_simple(struct nl_sock *sk, int flags, uint8_t family,
*/
static const struct trans_tbl idiag_states[] = {
- __ADD(IDIAG_SS_UNKNOWN, unknown)
- __ADD(IDIAG_SS_ESTABLISHED, established)
- __ADD(IDIAG_SS_SYN_SENT, syn_sent)
- __ADD(IDIAG_SS_SYN_RECV, syn_recv)
- __ADD(IDIAG_SS_FIN_WAIT1, fin_wait)
- __ADD(IDIAG_SS_FIN_WAIT2, fin_wait2)
- __ADD(IDIAG_SS_TIME_WAIT, time_wait)
- __ADD(IDIAG_SS_CLOSE, close)
- __ADD(IDIAG_SS_CLOSE_WAIT, close_wait)
- __ADD(IDIAG_SS_LAST_ACK, last_ack)
- __ADD(IDIAG_SS_LISTEN, listen)
- __ADD(IDIAG_SS_CLOSING, closing)
- __ADD(IDIAG_SS_MAX, max)
- { ((1<<IDIAG_SS_MAX)-1), "all" }
+ __ADD(TCP_ESTABLISHED, established),
+ __ADD(TCP_SYN_SENT, syn_sent),
+ __ADD(TCP_SYN_RECV, syn_recv),
+ __ADD(TCP_FIN_WAIT1, fin_wait),
+ __ADD(TCP_FIN_WAIT2, fin_wait2),
+ __ADD(TCP_TIME_WAIT, time_wait),
+ __ADD(TCP_CLOSE, close),
+ __ADD(TCP_CLOSE_WAIT, close_wait),
+ __ADD(TCP_LAST_ACK, last_ack),
+ __ADD(TCP_LISTEN, listen),
+ __ADD(TCP_CLOSING, closing),
};
/**
* Convert inet diag socket states to strings.
- * @arg state inetdiag socket state (e.g., IDIAG_SS_ESTABLISHED)
+ * @arg state inetdiag socket state (e.g., TCP_ESTABLISHED)
* @arg buf output buffer which will hold string result
* @arg len length in bytes of the output buffer
*
@@ -126,17 +126,17 @@ int idiagnl_str2state(const char *name)
}
static const struct trans_tbl idiag_timers[] = {
- __ADD(IDIAG_TIMER_OFF, off)
- __ADD(IDIAG_TIMER_ON, on)
- __ADD(IDIAG_TIMER_KEEPALIVE, keepalive)
- __ADD(IDIAG_TIMER_TIMEWAIT, timewait)
- __ADD(IDIAG_TIMER_PERSIST, persist)
- __ADD(IDIAG_TIMER_UNKNOWN, unknown)
+ __ADD(IDIAGNL_TIMER_OFF, off),
+ __ADD(IDIAGNL_TIMER_ON, on),
+ __ADD(IDIAGNL_TIMER_KEEPALIVE, keepalive),
+ __ADD(IDIAGNL_TIMER_TIMEWAIT, timewait),
+ __ADD(IDIAGNL_TIMER_PERSIST, persist),
+ __ADD(IDIAGNL_TIMER_UNKNOWN, unknown),
};
/**
* Convert inet diag timer types to strings.
- * @arg timer inetdiag timer (e.g., IDIAG_TIMER_ON)
+ * @arg timer inetdiag timer (e.g., IDIAGNL_TIMER_ON)
* @arg buf output buffer which will hold string result
* @arg len length in bytes of the output buffer
*
@@ -160,34 +160,61 @@ int idiagnl_str2timer(const char *name)
}
static const struct trans_tbl idiag_attrs[] = {
- __ADD(IDIAG_ATTR_NONE, none)
- __ADD(IDIAG_ATTR_MEMINFO, meminfo)
- __ADD(IDIAG_ATTR_INFO, info)
- __ADD(IDIAG_ATTR_VEGASINFO, vegasinfo)
- __ADD(IDIAG_ATTR_CONG, congestion)
- __ADD(IDIAG_ATTR_TOS, tos)
- __ADD(IDIAG_ATTR_TCLASS, tclass)
+ __ADD(INET_DIAG_NONE, none),
+ __ADD(INET_DIAG_MEMINFO, meminfo),
+ __ADD(INET_DIAG_INFO, info),
+ __ADD(INET_DIAG_VEGASINFO, vegasinfo),
+ __ADD(INET_DIAG_CONG, congestion),
+ __ADD(INET_DIAG_TOS, tos),
+ __ADD(INET_DIAG_TCLASS, tclass),
+ __ADD(INET_DIAG_SKMEMINFO, skmeminfo),
+ __ADD(INET_DIAG_SHUTDOWN, shutdown),
};
/**
- * Convert inetdiag extended attributes to strings.
- * @arg attrs inetdiag attribute (e.g., IDIAG_ATTR_MEMINFO)
+ * Convert inet diag extension type to a string.
+ * @arg attrs inet diag extension type (e.g. INET_DIAG_MEMINFO)
* @arg buf output buffer which will hold string result
* @arg len length in bytes of the output buffer
*
- * @return string representation of attrs or an empty string.
+ * @return string representation of inet diag extension type or an empty string.
+ * @deprecated: don't use this function. It is not very useful and should
+ * never have been exposed as public API.
*/
char *idiagnl_attrs2str(int attrs, char *buf, size_t len)
{
return __type2str(attrs, buf, len, idiag_attrs, ARRAY_SIZE(idiag_attrs));
}
+static const struct trans_tbl idiag_exts[] = {
+ __ADD((1 << (INET_DIAG_MEMINFO - 1)), meminfo),
+ __ADD((1 << (INET_DIAG_INFO - 1)), info),
+ __ADD((1 << (INET_DIAG_VEGASINFO - 1)), vegasinfo),
+ __ADD((1 << (INET_DIAG_CONG - 1)), congestion),
+ __ADD((1 << (INET_DIAG_TOS - 1)), tos),
+ __ADD((1 << (INET_DIAG_TCLASS - 1)), tclass),
+ __ADD((1 << (INET_DIAG_SKMEMINFO - 1)), skmeminfo),
+ __ADD((1 << (INET_DIAG_SHUTDOWN - 1)), shutdown),
+};
+
+/**
+ * Convert inet diag extension flags to a string.
+ * @arg attrs inet diag extension flags (e.g.
+ * ( (1<<(INET_DIAG_MEMINFO-1)) | (1<<(INET_DIAG_CONG-1)) | (1<<(INET_DIAG_TOS-1)) ) )
+ * @arg buf Output buffer to hold string representation
+ * @arg len length in bytes of the output buffer
+ */
+char *idiagnl_exts2str(uint8_t attrs, char *buf, size_t len)
+{
+ return __flags2str(attrs, buf, len, idiag_exts, ARRAY_SIZE(idiag_exts));
+}
+
static const struct trans_tbl idiagnl_tcpstates[] = {
- __ADD(TCP_CA_Open, open)
- __ADD(TCP_CA_Disorder, disorder)
- __ADD(TCP_CA_CWR, cwr)
- __ADD(TCP_CA_Recovery, recovery)
- __ADD(TCP_CA_Loss, loss)
+ __ADD(TCP_CA_Open, open),
+ __ADD(TCP_CA_Disorder, disorder),
+ __ADD(TCP_CA_CWR, cwr),
+ __ADD(TCP_CA_Recovery, recovery),
+ __ADD(TCP_CA_Loss, loss),
};
/**
@@ -203,10 +230,10 @@ char *idiagnl_tcpstate2str(uint8_t state, char *buf, size_t len)
}
static const struct trans_tbl idiagnl_tcpopt_attrs[] = {
- __ADD(TCPI_OPT_TIMESTAMPS, timestamps)
- __ADD(TCPI_OPT_SACK, sACK)
- __ADD(TCPI_OPT_WSCALE, wscale)
- __ADD(TCPI_OPT_ECN, ecn)
+ __ADD(TCPI_OPT_TIMESTAMPS, timestamps),
+ __ADD(TCPI_OPT_SACK, sACK),
+ __ADD(TCPI_OPT_WSCALE, wscale),
+ __ADD(TCPI_OPT_ECN, ecn),
};
/**
@@ -234,40 +261,18 @@ char *idiagnl_tcpopts2str(uint8_t attrs, char *buf, size_t len)
*/
char * idiagnl_shutdown2str(uint8_t shutdown, char *buf, size_t len)
{
- if (shutdown == 0) {
- snprintf(buf, len, " ");
- return buf;
- } else if (shutdown == 1) {
- snprintf(buf, len, "receive shutdown");
- return buf;
- } else if (shutdown == 2) {
- snprintf(buf, len, "send shutdown");
- return buf;
- }
+ if (shutdown == 0) {
+ snprintf(buf, len, " ");
+ return buf;
+ } else if (shutdown == 1) {
+ snprintf(buf, len, "receive shutdown");
+ return buf;
+ } else if (shutdown == 2) {
+ snprintf(buf, len, "send shutdown");
+ return buf;
+ }
- return NULL;
-}
-
-static const struct trans_tbl idiag_exts[] = {
- __ADD(IDIAG_ATTR_NONE, none)
- __ADD(IDIAG_ATTR_MEMINFO, meminfo)
- __ADD(IDIAG_ATTR_INFO, info)
- __ADD(IDIAG_ATTR_VEGASINFO, vegasinfo)
- __ADD(IDIAG_ATTR_CONG, congestion)
- __ADD(IDIAG_ATTR_TOS, tos)
- __ADD(IDIAG_ATTR_TCLASS, tclass)
-};
-
-/**
- * Convert inet diag extension flags to a string.
- * @arg attrs inet diag extension flags (e.g., (IDIAG_ATTR_MEMINFO |
- * IDIAG_ATTR_CONG | IDIAG_ATTR_TOS))
- * @arg buf Output buffer to hold string representation
- * @arg len length in bytes of the output buffer
- */
-char *idiagnl_exts2str(uint8_t attrs, char *buf, size_t len)
-{
- return __flags2str(attrs, buf, len, idiag_exts, ARRAY_SIZE(idiag_exts));
+ return NULL;
}
/** @} */
diff --git a/lib/idiag/idiag_meminfo_obj.c b/lib/idiag/idiag_meminfo_obj.c
index a60f4979..0ada71ee 100644
--- a/lib/idiag/idiag_meminfo_obj.c
+++ b/lib/idiag/idiag_meminfo_obj.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/idiag/idiagnl_meminfo_obj.c Inet Diag Meminfo Object
*
@@ -80,21 +81,25 @@ void idiagnl_meminfo_set_tmem(struct idiagnl_meminfo *minfo, uint32_t tmem)
}
/** @} */
-static int idiagnl_meminfo_clone(struct nl_object *_dst, struct nl_object *_src)
+/** @cond SKIP */
+static uint64_t idiagnl_meminfo_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
- struct idiagnl_meminfo *dst = (struct idiagnl_meminfo *) _dst;
- struct idiagnl_meminfo *src = (struct idiagnl_meminfo *) _src;
-
- memcpy(dst, src, sizeof(struct idiagnl_meminfo));
-
- return 0;
+ struct idiagnl_meminfo *a = (struct idiagnl_meminfo *) _a;
+ struct idiagnl_meminfo *b = (struct idiagnl_meminfo *) _b;
+
+ /* meminfo is a very simple object. It has no attribe flags (ce_mask),
+ * hence compare just returns 0 or 1, not a bit mask of attributes. */
+ return a->idiag_rmem != b->idiag_rmem ||
+ a->idiag_wmem != b->idiag_wmem ||
+ a->idiag_fmem != b->idiag_fmem ||
+ a->idiag_tmem != b->idiag_tmem;
}
-/** @cond SKIP */
struct nl_object_ops idiagnl_meminfo_obj_ops = {
.oo_name = "idiag/idiag_meminfo",
.oo_size = sizeof(struct idiagnl_meminfo),
- .oo_clone = idiagnl_meminfo_clone,
+ .oo_compare = idiagnl_meminfo_compare,
};
/** @endcond */
/** @} */
diff --git a/lib/idiag/idiag_msg_obj.c b/lib/idiag/idiag_msg_obj.c
index 19e6c5be..a1beb2c7 100644
--- a/lib/idiag/idiag_msg_obj.c
+++ b/lib/idiag/idiag_msg_obj.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/idiag/idiagnl_msg_obj.c Inet Diag Message Object
*
@@ -10,11 +11,40 @@
*/
#include <netlink-private/netlink.h>
+#include <netlink/hashtable.h>
#include <netlink/idiag/msg.h>
#include <netlink/idiag/meminfo.h>
#include <netlink/idiag/vegasinfo.h>
#include <linux/inet_diag.h>
+
+/** @cond SKIP */
+#define IDIAGNL_ATTR_FAMILY (0x1 << 1)
+#define IDIAGNL_ATTR_STATE (0x1 << 2)
+#define IDIAGNL_ATTR_TIMER (0x1 << 3)
+#define IDIAGNL_ATTR_RETRANS (0x1 << 4)
+#define IDIAGNL_ATTR_SPORT (0x1 << 5)
+#define IDIAGNL_ATTR_DPORT (0x1 << 6)
+#define IDIAGNL_ATTR_SRC (0x1 << 7)
+#define IDIAGNL_ATTR_DST (0x1 << 8)
+#define IDIAGNL_ATTR_IFINDEX (0x1 << 9)
+#define IDIAGNL_ATTR_EXPIRES (0x1 << 10)
+#define IDIAGNL_ATTR_RQUEUE (0x1 << 11)
+#define IDIAGNL_ATTR_WQUEUE (0x1 << 12)
+#define IDIAGNL_ATTR_UID (0x1 << 13)
+#define IDIAGNL_ATTR_INODE (0x1 << 14)
+#define IDIAGNL_ATTR_TOS (0x1 << 15)
+#define IDIAGNL_ATTR_TCLASS (0x1 << 16)
+#define IDIAGNL_ATTR_SHUTDOWN (0x1 << 17)
+#define IDIAGNL_ATTR_CONG (0x1 << 18)
+#define IDIAGNL_ATTR_MEMINFO (0x1 << 19)
+#define IDIAGNL_ATTR_VEGASINFO (0x1 << 20)
+#define IDIAGNL_ATTR_TCPINFO (0x1 << 21)
+#define IDIAGNL_ATTR_SKMEMINFO (0x1 << 22)
+
+#define _INET_DIAG_ALL ((1<<(INET_DIAG_MAX+1))-1)
+/** @endcond */
+
/**
* @ingroup idiag
* @defgroup idiagnl_msg Inet Diag Messages
@@ -60,15 +90,25 @@ static int idiagnl_request_update(struct nl_cache *cache, struct nl_sock *sk)
int family = cache->c_iarg1;
int states = cache->c_iarg2;
- return idiagnl_send_simple(sk, 0, family, states, IDIAG_ATTR_ALL);
+ /* idiagnl_send_simple()'s "ext" argument is u16, which is too small for _INET_DIAG_ALL,
+ * which is more than 16 bits on recent kernels.
+ *
+ * Actually, internally idiagnl_send_simple() sets "struct inet_diag_req"'s "idiag_ext"
+ * field, which is only 8 bits. So, it's even worse.
+ *
+ * FIXME: this probably should be fixed (by adding idiagnl_send_simple2() function), but for
+ * the moment it means we cannot request more than 0xFF.
+ */
+
+ return idiagnl_send_simple(sk, 0, family, states, (uint16_t) _INET_DIAG_ALL);
}
static struct nl_cache_ops idiagnl_msg_ops = {
.co_name = "idiag/idiag",
.co_hdrsize = sizeof(struct inet_diag_msg),
.co_msgtypes = {
- { IDIAG_TCPDIAG_GETSOCK, NL_ACT_NEW, "new" },
- { IDIAG_DCCPDIAG_GETSOCK, NL_ACT_NEW, "new" },
+ { TCPDIAG_GETSOCK, NL_ACT_NEW, "new" },
+ { DCCPDIAG_GETSOCK, NL_ACT_NEW, "new" },
END_OF_MSGTYPES_LIST,
},
.co_protocol = NETLINK_INET_DIAG,
@@ -139,6 +179,7 @@ uint8_t idiagnl_msg_get_family(const struct idiagnl_msg *msg)
void idiagnl_msg_set_family(struct idiagnl_msg *msg, uint8_t family)
{
msg->idiag_family = family;
+ msg->ce_mask |= IDIAGNL_ATTR_FAMILY;
}
uint8_t idiagnl_msg_get_state(const struct idiagnl_msg *msg)
@@ -149,6 +190,7 @@ uint8_t idiagnl_msg_get_state(const struct idiagnl_msg *msg)
void idiagnl_msg_set_state(struct idiagnl_msg *msg, uint8_t state)
{
msg->idiag_state = state;
+ msg->ce_mask |= IDIAGNL_ATTR_STATE;
}
uint8_t idiagnl_msg_get_timer(const struct idiagnl_msg *msg)
@@ -159,6 +201,7 @@ uint8_t idiagnl_msg_get_timer(const struct idiagnl_msg *msg)
void idiagnl_msg_set_timer(struct idiagnl_msg *msg, uint8_t timer)
{
msg->idiag_timer = timer;
+ msg->ce_mask |= IDIAGNL_ATTR_TIMER;
}
uint8_t idiagnl_msg_get_retrans(const struct idiagnl_msg *msg)
@@ -169,6 +212,7 @@ uint8_t idiagnl_msg_get_retrans(const struct idiagnl_msg *msg)
void idiagnl_msg_set_retrans(struct idiagnl_msg *msg, uint8_t retrans)
{
msg->idiag_retrans = retrans;
+ msg->ce_mask |= IDIAGNL_ATTR_RETRANS;
}
uint16_t idiagnl_msg_get_sport(struct idiagnl_msg *msg)
@@ -179,6 +223,7 @@ uint16_t idiagnl_msg_get_sport(struct idiagnl_msg *msg)
void idiagnl_msg_set_sport(struct idiagnl_msg *msg, uint16_t port)
{
msg->idiag_sport = port;
+ msg->ce_mask |= IDIAGNL_ATTR_SPORT;
}
uint16_t idiagnl_msg_get_dport(struct idiagnl_msg *msg)
@@ -189,6 +234,7 @@ uint16_t idiagnl_msg_get_dport(struct idiagnl_msg *msg)
void idiagnl_msg_set_dport(struct idiagnl_msg *msg, uint16_t port)
{
msg->idiag_dport = port;
+ msg->ce_mask |= IDIAGNL_ATTR_DPORT;
}
struct nl_addr *idiagnl_msg_get_src(const struct idiagnl_msg *msg)
@@ -203,6 +249,7 @@ int idiagnl_msg_set_src(struct idiagnl_msg *msg, struct nl_addr *addr)
nl_addr_get(addr);
msg->idiag_src = addr;
+ msg->ce_mask |= IDIAGNL_ATTR_SRC;
return 0;
}
@@ -219,6 +266,7 @@ int idiagnl_msg_set_dst(struct idiagnl_msg *msg, struct nl_addr *addr)
nl_addr_get(addr);
msg->idiag_dst = addr;
+ msg->ce_mask |= IDIAGNL_ATTR_DST;
return 0;
}
@@ -231,6 +279,7 @@ uint32_t idiagnl_msg_get_ifindex(const struct idiagnl_msg *msg)
void idiagnl_msg_set_ifindex(struct idiagnl_msg *msg, uint32_t ifindex)
{
msg->idiag_ifindex = ifindex;
+ msg->ce_mask |= IDIAGNL_ATTR_IFINDEX;
}
uint32_t idiagnl_msg_get_expires(const struct idiagnl_msg *msg)
@@ -241,6 +290,7 @@ uint32_t idiagnl_msg_get_expires(const struct idiagnl_msg *msg)
void idiagnl_msg_set_expires(struct idiagnl_msg *msg, uint32_t expires)
{
msg->idiag_expires = expires;
+ msg->ce_mask |= IDIAGNL_ATTR_EXPIRES;
}
uint32_t idiagnl_msg_get_rqueue(const struct idiagnl_msg *msg)
@@ -251,6 +301,7 @@ uint32_t idiagnl_msg_get_rqueue(const struct idiagnl_msg *msg)
void idiagnl_msg_set_rqueue(struct idiagnl_msg *msg, uint32_t rqueue)
{
msg->idiag_rqueue = rqueue;
+ msg->ce_mask |= IDIAGNL_ATTR_RQUEUE;
}
uint32_t idiagnl_msg_get_wqueue(const struct idiagnl_msg *msg)
@@ -261,6 +312,7 @@ uint32_t idiagnl_msg_get_wqueue(const struct idiagnl_msg *msg)
void idiagnl_msg_set_wqueue(struct idiagnl_msg *msg, uint32_t wqueue)
{
msg->idiag_wqueue = wqueue;
+ msg->ce_mask |= IDIAGNL_ATTR_WQUEUE;
}
uint32_t idiagnl_msg_get_uid(const struct idiagnl_msg *msg)
@@ -271,6 +323,7 @@ uint32_t idiagnl_msg_get_uid(const struct idiagnl_msg *msg)
void idiagnl_msg_set_uid(struct idiagnl_msg *msg, uint32_t uid)
{
msg->idiag_uid = uid;
+ msg->ce_mask |= IDIAGNL_ATTR_UID;
}
uint32_t idiagnl_msg_get_inode(const struct idiagnl_msg *msg)
@@ -281,6 +334,7 @@ uint32_t idiagnl_msg_get_inode(const struct idiagnl_msg *msg)
void idiagnl_msg_set_inode(struct idiagnl_msg *msg, uint32_t inode)
{
msg->idiag_inode = inode;
+ msg->ce_mask |= IDIAGNL_ATTR_INODE;
}
uint8_t idiagnl_msg_get_tos(const struct idiagnl_msg *msg)
@@ -291,6 +345,7 @@ uint8_t idiagnl_msg_get_tos(const struct idiagnl_msg *msg)
void idiagnl_msg_set_tos(struct idiagnl_msg *msg, uint8_t tos)
{
msg->idiag_tos = tos;
+ msg->ce_mask |= IDIAGNL_ATTR_TOS;
}
uint8_t idiagnl_msg_get_tclass(const struct idiagnl_msg *msg)
@@ -301,6 +356,7 @@ uint8_t idiagnl_msg_get_tclass(const struct idiagnl_msg *msg)
void idiagnl_msg_set_tclass(struct idiagnl_msg *msg, uint8_t tclass)
{
msg->idiag_tclass = tclass;
+ msg->ce_mask |= IDIAGNL_ATTR_TCLASS;
}
uint8_t idiagnl_msg_get_shutdown(const struct idiagnl_msg *msg)
@@ -311,6 +367,7 @@ uint8_t idiagnl_msg_get_shutdown(const struct idiagnl_msg *msg)
void idiagnl_msg_set_shutdown(struct idiagnl_msg *msg, uint8_t shutdown)
{
msg->idiag_shutdown = shutdown;
+ msg->ce_mask |= IDIAGNL_ATTR_SHUTDOWN;
}
char *idiagnl_msg_get_cong(const struct idiagnl_msg *msg)
@@ -320,7 +377,9 @@ char *idiagnl_msg_get_cong(const struct idiagnl_msg *msg)
void idiagnl_msg_set_cong(struct idiagnl_msg *msg, char *cong)
{
+ free (msg->idiag_cong);
msg->idiag_cong = strdup(cong);
+ msg->ce_mask |= IDIAGNL_ATTR_CONG;
}
struct idiagnl_meminfo *idiagnl_msg_get_meminfo(const struct idiagnl_msg *msg)
@@ -328,14 +387,14 @@ struct idiagnl_meminfo *idiagnl_msg_get_meminfo(const struct idiagnl_msg *msg)
return msg->idiag_meminfo;
}
-void idiagnl_msg_set_meminfo(struct idiagnl_msg *msg, struct idiagnl_meminfo
- *minfo)
+void idiagnl_msg_set_meminfo(struct idiagnl_msg *msg, struct idiagnl_meminfo *minfo)
{
if (msg->idiag_meminfo)
idiagnl_meminfo_put(msg->idiag_meminfo);
idiagnl_meminfo_get(minfo);
msg->idiag_meminfo = minfo;
+ msg->ce_mask |= IDIAGNL_ATTR_MEMINFO;
}
struct idiagnl_vegasinfo *idiagnl_msg_get_vegasinfo(const struct idiagnl_msg *msg)
@@ -343,14 +402,14 @@ struct idiagnl_vegasinfo *idiagnl_msg_get_vegasinfo(const struct idiagnl_msg *ms
return msg->idiag_vegasinfo;
}
-void idiagnl_msg_set_vegasinfo(struct idiagnl_msg *msg, struct idiagnl_vegasinfo
- *vinfo)
+void idiagnl_msg_set_vegasinfo(struct idiagnl_msg *msg, struct idiagnl_vegasinfo *vinfo)
{
if (msg->idiag_vegasinfo)
idiagnl_vegasinfo_put(msg->idiag_vegasinfo);
idiagnl_vegasinfo_get(vinfo);
msg->idiag_vegasinfo = vinfo;
+ msg->ce_mask |= IDIAGNL_ATTR_VEGASINFO;
}
struct tcp_info idiagnl_msg_get_tcpinfo(const struct idiagnl_msg *msg)
@@ -361,6 +420,7 @@ struct tcp_info idiagnl_msg_get_tcpinfo(const struct idiagnl_msg *msg)
void idiagnl_msg_set_tcpinfo(struct idiagnl_msg *msg, struct tcp_info *tinfo)
{
memcpy(&msg->idiag_tcpinfo, tinfo, sizeof(struct tcp_info));
+ msg->ce_mask |= IDIAGNL_ATTR_TCPINFO;
}
/** @} */
@@ -409,7 +469,7 @@ static void idiag_msg_dump_details(struct nl_object *a, struct nl_dump_params *p
nl_dump(p, "tos: 0x%x\n", msg->idiag_tos);
nl_dump(p, "traffic class: %d\n", msg->idiag_tclass);
- nl_dump(p, "congestion algorithm: %s\n", msg->idiag_cong);
+ nl_dump(p, "congestion algorithm: %s\n", msg->idiag_cong ? msg->idiag_cong : "");
}
static void idiag_msg_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
@@ -526,27 +586,29 @@ static void idiag_msg_dump_stats(struct nl_object *obj, struct nl_dump_params *p
nl_dump(p, "]\n");
}
- nl_dump(p, "skmeminfo: [\n");
- nl_dump(p, "\trmem alloc: %d\n",
- msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_RMEM_ALLOC]);
- nl_dump(p, "\trcv buf: %s\n",
- nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_RCVBUF],
- buf, sizeof(buf)));
- nl_dump(p, "\twmem alloc: %d\n",
- msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_WMEM_ALLOC]);
- nl_dump(p, "\tsnd buf: %s\n",
- nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_SNDBUF],
- buf, sizeof(buf)));
- nl_dump(p, "\tfwd alloc: %d\n",
- msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_FWD_ALLOC]);
- nl_dump(p, "\twmem queued: %s\n",
- nl_size2str(msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_WMEM_QUEUED],
- buf, sizeof(buf)));
- nl_dump(p, "\topt mem: %d\n",
- msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_OPTMEM]);
- nl_dump(p, "\tbacklog: %d\n",
- msg->idiag_skmeminfo[IDIAG_SK_MEMINFO_BACKLOG]);
- nl_dump(p, "]\n\n");
+ if (msg->ce_mask & IDIAGNL_ATTR_MEMINFO) {
+ nl_dump(p, "skmeminfo: [\n");
+ nl_dump(p, "\trmem alloc: %d\n",
+ msg->idiag_skmeminfo[SK_MEMINFO_RMEM_ALLOC]);
+ nl_dump(p, "\trcv buf: %s\n",
+ nl_size2str(msg->idiag_skmeminfo[SK_MEMINFO_RCVBUF],
+ buf, sizeof(buf)));
+ nl_dump(p, "\twmem alloc: %d\n",
+ msg->idiag_skmeminfo[SK_MEMINFO_WMEM_ALLOC]);
+ nl_dump(p, "\tsnd buf: %s\n",
+ nl_size2str(msg->idiag_skmeminfo[SK_MEMINFO_SNDBUF],
+ buf, sizeof(buf)));
+ nl_dump(p, "\tfwd alloc: %d\n",
+ msg->idiag_skmeminfo[SK_MEMINFO_FWD_ALLOC]);
+ nl_dump(p, "\twmem queued: %s\n",
+ nl_size2str(msg->idiag_skmeminfo[SK_MEMINFO_WMEM_QUEUED],
+ buf, sizeof(buf)));
+ nl_dump(p, "\topt mem: %d\n",
+ msg->idiag_skmeminfo[SK_MEMINFO_OPTMEM]);
+ nl_dump(p, "\tbacklog: %d\n",
+ msg->idiag_skmeminfo[SK_MEMINFO_BACKLOG]);
+ nl_dump(p, "]\n\n");
+ }
}
static void idiagnl_msg_free(struct nl_object *a)
@@ -567,26 +629,60 @@ static int idiagnl_msg_clone(struct nl_object *_dst, struct nl_object *_src)
struct idiagnl_msg *dst = (struct idiagnl_msg *) _dst;
struct idiagnl_msg *src = (struct idiagnl_msg *) _src;
- if (src->idiag_src)
+ dst->idiag_cong = NULL;
+ dst->idiag_src = NULL;
+ dst->idiag_dst = NULL;
+ dst->idiag_meminfo = NULL;
+ dst->idiag_vegasinfo = NULL;
+ dst->ce_mask &= ~(IDIAGNL_ATTR_CONG |
+ IDIAGNL_ATTR_SRC |
+ IDIAGNL_ATTR_DST |
+ IDIAGNL_ATTR_MEMINFO |
+ IDIAGNL_ATTR_VEGASINFO);
+
+ if (src->idiag_cong) {
+ if (!(dst->idiag_cong = strdup(src->idiag_cong)))
+ return -NLE_NOMEM;
+ dst->ce_mask |= IDIAGNL_ATTR_CONG;
+ }
+
+ if (src->idiag_src) {
if (!(dst->idiag_src = nl_addr_clone(src->idiag_src)))
return -NLE_NOMEM;
+ dst->ce_mask |= IDIAGNL_ATTR_SRC;
+ }
- if (src->idiag_dst)
+ if (src->idiag_dst) {
if (!(dst->idiag_dst = nl_addr_clone(src->idiag_dst)))
return -NLE_NOMEM;
+ dst->ce_mask |= IDIAGNL_ATTR_DST;
+ }
+
+ if (src->idiag_meminfo) {
+ if (!(dst->idiag_meminfo = (struct idiagnl_meminfo *) nl_object_clone((struct nl_object *) src->idiag_meminfo)))
+ return -NLE_NOMEM;
+ dst->ce_mask |= IDIAGNL_ATTR_MEMINFO;
+ }
+
+ if (src->idiag_vegasinfo) {
+ if (!(dst->idiag_vegasinfo = (struct idiagnl_vegasinfo *) nl_object_clone((struct nl_object *) src->idiag_vegasinfo)))
+ return -NLE_NOMEM;
+ dst->ce_mask |= IDIAGNL_ATTR_VEGASINFO;
+ }
return 0;
}
-static struct nla_policy ext_policy[IDIAG_ATTR_MAX] = {
- [IDIAG_ATTR_MEMINFO] = { .minlen = sizeof(struct inet_diag_meminfo) },
- [IDIAG_ATTR_INFO] = { .minlen = sizeof(struct tcp_info) },
- [IDIAG_ATTR_VEGASINFO] = { .minlen = sizeof(struct tcpvegas_info) },
- [IDIAG_ATTR_CONG] = { .type = NLA_STRING },
- [IDIAG_ATTR_TOS] = { .type = NLA_U8 },
- [IDIAG_ATTR_TCLASS] = { .type = NLA_U8 },
- [IDIAG_ATTR_SKMEMINFO] = { .minlen = (sizeof(uint32_t) * IDIAG_SK_MEMINFO_VARS) },
- [IDIAG_ATTR_SHUTDOWN] = { .type = NLA_U8 },
+static struct nla_policy ext_policy[INET_DIAG_MAX+1] = {
+ [INET_DIAG_MEMINFO] = { .minlen = sizeof(struct inet_diag_meminfo) },
+ [INET_DIAG_INFO] = { .minlen = sizeof(struct tcp_info) },
+ [INET_DIAG_VEGASINFO] = { .minlen = sizeof(struct tcpvegas_info) },
+ [INET_DIAG_CONG] = { .type = NLA_STRING },
+ [INET_DIAG_TOS] = { .type = NLA_U8 },
+ [INET_DIAG_TCLASS] = { .type = NLA_U8 },
+ /* Older kernel doesn't have SK_MEMINFO_BACKLOG */
+ [INET_DIAG_SKMEMINFO] = { .minlen = (sizeof(uint32_t) * (SK_MEMINFO_OPTMEM + 1)) },
+ [INET_DIAG_SHUTDOWN] = { .type = NLA_U8 },
};
int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result)
@@ -594,14 +690,14 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result)
struct idiagnl_msg *msg = NULL;
struct inet_diag_msg *raw_msg = NULL;
struct nl_addr *src = NULL, *dst = NULL;
- struct nlattr *tb[IDIAG_ATTR_MAX];
+ struct nlattr *tb[INET_DIAG_MAX+1];
int err = 0;
msg = idiagnl_msg_alloc();
if (!msg)
goto errout_nomem;
- err = nlmsg_parse(nlh, sizeof(struct inet_diag_msg), tb, IDIAG_ATTR_MAX,
+ err = nlmsg_parse(nlh, sizeof(struct inet_diag_msg), tb, INET_DIAG_MAX,
ext_policy);
if (err < 0)
goto errout;
@@ -620,6 +716,19 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result)
msg->idiag_dport = raw_msg->id.idiag_dport;
msg->idiag_ifindex = raw_msg->id.idiag_if;
+ msg->ce_mask = (IDIAGNL_ATTR_FAMILY |
+ IDIAGNL_ATTR_STATE |
+ IDIAGNL_ATTR_TIMER |
+ IDIAGNL_ATTR_RETRANS |
+ IDIAGNL_ATTR_EXPIRES |
+ IDIAGNL_ATTR_RQUEUE |
+ IDIAGNL_ATTR_WQUEUE |
+ IDIAGNL_ATTR_UID |
+ IDIAGNL_ATTR_INODE |
+ IDIAGNL_ATTR_SPORT |
+ IDIAGNL_ATTR_DPORT |
+ IDIAGNL_ATTR_IFINDEX);
+
dst = nl_addr_build(raw_msg->idiag_family, raw_msg->id.idiag_dst,
sizeof(raw_msg->id.idiag_dst));
if (!dst)
@@ -642,23 +751,33 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result)
nl_addr_put(src);
- if (tb[IDIAG_ATTR_TOS])
- msg->idiag_tos = nla_get_u8(tb[IDIAG_ATTR_TOS]);
+ if (tb[INET_DIAG_TOS]) {
+ msg->idiag_tos = nla_get_u8(tb[INET_DIAG_TOS]);
+ msg->ce_mask |= IDIAGNL_ATTR_TOS;
+ }
- if (tb[IDIAG_ATTR_TCLASS])
- msg->idiag_tclass = nla_get_u8(tb[IDIAG_ATTR_TCLASS]);
+ if (tb[INET_DIAG_TCLASS]) {
+ msg->idiag_tclass = nla_get_u8(tb[INET_DIAG_TCLASS]);
+ msg->ce_mask |= IDIAGNL_ATTR_TCLASS;
+ }
- if (tb[IDIAG_ATTR_SHUTDOWN])
- msg->idiag_shutdown = nla_get_u8(tb[IDIAG_ATTR_SHUTDOWN]);
+ if (tb[INET_DIAG_SHUTDOWN]) {
+ msg->idiag_shutdown = nla_get_u8(tb[INET_DIAG_SHUTDOWN]);
+ msg->ce_mask |= IDIAGNL_ATTR_SHUTDOWN;
+ }
- if (tb[IDIAG_ATTR_CONG])
- msg->idiag_cong = nla_strdup(tb[IDIAG_ATTR_CONG]);
+ if (tb[INET_DIAG_CONG]) {
+ msg->idiag_cong = nla_strdup(tb[INET_DIAG_CONG]);
+ msg->ce_mask |= IDIAGNL_ATTR_CONG;
+ }
- if (tb[IDIAG_ATTR_INFO])
- nla_memcpy(&msg->idiag_tcpinfo, tb[IDIAG_ATTR_INFO],
+ if (tb[INET_DIAG_INFO]) {
+ nla_memcpy(&msg->idiag_tcpinfo, tb[INET_DIAG_INFO],
sizeof(msg->idiag_tcpinfo));
+ msg->ce_mask |= IDIAGNL_ATTR_TCPINFO;
+ }
- if (tb[IDIAG_ATTR_MEMINFO]) {
+ if (tb[INET_DIAG_MEMINFO]) {
struct idiagnl_meminfo *minfo = idiagnl_meminfo_alloc();
struct inet_diag_meminfo *raw_minfo = NULL;
@@ -666,7 +785,7 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result)
goto errout_nomem;
raw_minfo = (struct inet_diag_meminfo *)
- nla_data(tb[IDIAG_ATTR_MEMINFO]);
+ nla_data(tb[INET_DIAG_MEMINFO]);
idiagnl_meminfo_set_rmem(minfo, raw_minfo->idiag_rmem);
idiagnl_meminfo_set_wmem(minfo, raw_minfo->idiag_wmem);
@@ -674,9 +793,10 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result)
idiagnl_meminfo_set_tmem(minfo, raw_minfo->idiag_tmem);
msg->idiag_meminfo = minfo;
+ msg->ce_mask |= IDIAGNL_ATTR_MEMINFO;
}
- if (tb[IDIAG_ATTR_VEGASINFO]) {
+ if (tb[INET_DIAG_VEGASINFO]) {
struct idiagnl_vegasinfo *vinfo = idiagnl_vegasinfo_alloc();
struct tcpvegas_info *raw_vinfo = NULL;
@@ -684,7 +804,7 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result)
goto errout_nomem;
raw_vinfo = (struct tcpvegas_info *)
- nla_data(tb[IDIAG_ATTR_VEGASINFO]);
+ nla_data(tb[INET_DIAG_VEGASINFO]);
idiagnl_vegasinfo_set_enabled(vinfo, raw_vinfo->tcpv_enabled);
idiagnl_vegasinfo_set_rttcnt(vinfo, raw_vinfo->tcpv_rttcnt);
@@ -692,11 +812,14 @@ int idiagnl_msg_parse(struct nlmsghdr *nlh, struct idiagnl_msg **result)
idiagnl_vegasinfo_set_minrtt(vinfo, raw_vinfo->tcpv_minrtt);
msg->idiag_vegasinfo = vinfo;
+ msg->ce_mask |= IDIAGNL_ATTR_VEGASINFO;
}
- if (tb[IDIAG_ATTR_SKMEMINFO])
- nla_memcpy(&msg->idiag_skmeminfo, tb[IDIAG_ATTR_SKMEMINFO],
+ if (tb[INET_DIAG_SKMEMINFO]) {
+ nla_memcpy(&msg->idiag_skmeminfo, tb[INET_DIAG_SKMEMINFO],
sizeof(msg->idiag_skmeminfo));
+ msg->ce_mask |= IDIAGNL_ATTR_SKMEMINFO;
+ }
*result = msg;
return 0;
@@ -710,6 +833,108 @@ errout_nomem:
goto errout;
}
+static const struct trans_tbl idiagnl_attrs[] = {
+ __ADD(IDIAGNL_ATTR_FAMILY, family),
+ __ADD(IDIAGNL_ATTR_STATE, state),
+ __ADD(IDIAGNL_ATTR_TIMER, timer),
+ __ADD(IDIAGNL_ATTR_RETRANS, retrans),
+ __ADD(IDIAGNL_ATTR_SPORT, sport),
+ __ADD(IDIAGNL_ATTR_DPORT, dport),
+ __ADD(IDIAGNL_ATTR_SRC, src),
+ __ADD(IDIAGNL_ATTR_DST, dst),
+ __ADD(IDIAGNL_ATTR_IFINDEX, ifindex),
+ __ADD(IDIAGNL_ATTR_EXPIRES, expires),
+ __ADD(IDIAGNL_ATTR_RQUEUE, rqueue),
+ __ADD(IDIAGNL_ATTR_WQUEUE, wqueue),
+ __ADD(IDIAGNL_ATTR_UID, uid),
+ __ADD(IDIAGNL_ATTR_INODE, inode),
+ __ADD(IDIAGNL_ATTR_TOS, tos),
+ __ADD(IDIAGNL_ATTR_TCLASS, tclass),
+ __ADD(IDIAGNL_ATTR_SHUTDOWN, shutdown),
+ __ADD(IDIAGNL_ATTR_CONG, cong),
+ __ADD(IDIAGNL_ATTR_MEMINFO, meminfo),
+ __ADD(IDIAGNL_ATTR_VEGASINFO, vegasinfo),
+ __ADD(IDIAGNL_ATTR_TCPINFO, tcpinfo),
+ __ADD(IDIAGNL_ATTR_SKMEMINFO, skmeminfo),
+};
+
+static char *_idiagnl_attrs2str(int attrs, char *buf, size_t len)
+{
+ return __flags2str(attrs, buf, len, idiagnl_attrs,
+ ARRAY_SIZE(idiagnl_attrs));
+}
+
+static uint64_t idiagnl_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
+{
+ struct idiagnl_msg *a = (struct idiagnl_msg *) _a;
+ struct idiagnl_msg *b = (struct idiagnl_msg *) _b;
+ uint64_t diff = 0;
+
+#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, IDIAGNL_ATTR_##ATTR, a, b, EXPR)
+ diff |= _DIFF(FAMILY, a->idiag_family != b->idiag_family);
+ diff |= _DIFF(STATE, a->idiag_state != b->idiag_state);
+ diff |= _DIFF(TIMER, a->idiag_timer != b->idiag_timer);
+ diff |= _DIFF(RETRANS, a->idiag_retrans != b->idiag_retrans);
+ diff |= _DIFF(SPORT, a->idiag_sport != b->idiag_sport);
+ diff |= _DIFF(DPORT, a->idiag_dport != b->idiag_dport);
+ diff |= _DIFF(SRC, nl_addr_cmp (a->idiag_src, b->idiag_src));
+ diff |= _DIFF(DST, nl_addr_cmp (a->idiag_dst, b->idiag_dst));
+ diff |= _DIFF(IFINDEX, a->idiag_ifindex != b->idiag_ifindex);
+ diff |= _DIFF(EXPIRES, a->idiag_expires != b->idiag_expires);
+ diff |= _DIFF(RQUEUE, a->idiag_rqueue != b->idiag_rqueue);
+ diff |= _DIFF(WQUEUE, a->idiag_wqueue != b->idiag_wqueue);
+ diff |= _DIFF(UID, a->idiag_uid != b->idiag_uid);
+ diff |= _DIFF(INODE, a->idiag_inode != b->idiag_inode);
+ diff |= _DIFF(TOS, a->idiag_tos != b->idiag_tos);
+ diff |= _DIFF(TCLASS, a->idiag_tclass != b->idiag_tclass);
+ diff |= _DIFF(SHUTDOWN, a->idiag_shutdown != b->idiag_shutdown);
+ diff |= _DIFF(CONG, strcmp(a->idiag_cong, b->idiag_cong));
+ diff |= _DIFF(MEMINFO, nl_object_diff((struct nl_object *) a->idiag_meminfo, (struct nl_object *) b->idiag_meminfo));
+ diff |= _DIFF(VEGASINFO, nl_object_diff((struct nl_object *) a->idiag_vegasinfo, (struct nl_object *) b->idiag_vegasinfo));
+ diff |= _DIFF(TCPINFO, memcmp(&a->idiag_tcpinfo, &b->idiag_tcpinfo, sizeof(a->idiag_tcpinfo)));
+ diff |= _DIFF(SKMEMINFO, memcmp(a->idiag_skmeminfo, b->idiag_skmeminfo, sizeof(a->idiag_skmeminfo)));
+#undef _DIFF
+ return diff;
+}
+
+static void idiagnl_keygen(struct nl_object *obj, uint32_t *hashkey,
+ uint32_t table_sz)
+{
+ struct idiagnl_msg *msg = (struct idiagnl_msg *)obj;
+ unsigned int key_sz;
+ struct idiagnl_hash_key {
+ uint8_t family;
+ uint32_t src_hash;
+ uint32_t dst_hash;
+ uint16_t sport;
+ uint16_t dport;
+ } __attribute__((packed)) key;
+
+ key_sz = sizeof(key);
+ key.family = msg->idiag_family;
+ key.src_hash = 0;
+ key.dst_hash = 0;
+ key.sport = msg->idiag_sport;
+ key.dport = msg->idiag_dport;
+
+ if (msg->idiag_src) {
+ key.src_hash = nl_hash (nl_addr_get_binary_addr(msg->idiag_src),
+ nl_addr_get_len(msg->idiag_src), 0);
+ }
+ if (msg->idiag_dst) {
+ key.dst_hash = nl_hash (nl_addr_get_binary_addr(msg->idiag_dst),
+ nl_addr_get_len(msg->idiag_dst), 0);
+ }
+
+ *hashkey = nl_hash(&key, key_sz, 0) % table_sz;
+
+ NL_DBG(5, "idiagnl %p key (fam %d src_hash %d dst_hash %d sport %d dport %d) keysz %d, hash 0x%x\n",
+ msg, key.family, key.src_hash, key.dst_hash, key.sport, key.dport, key_sz, *hashkey);
+
+ return;
+}
+
/** @cond SKIP */
struct nl_object_ops idiagnl_msg_obj_ops = {
.oo_name = "idiag/idiag_msg",
@@ -721,8 +946,14 @@ struct nl_object_ops idiagnl_msg_obj_ops = {
[NL_DUMP_DETAILS] = idiag_msg_dump_details,
[NL_DUMP_STATS] = idiag_msg_dump_stats,
},
- .oo_attrs2str = idiagnl_attrs2str,
- .oo_id_attrs = (IDIAG_ATTR_INFO)
+ .oo_compare = idiagnl_compare,
+ .oo_keygen = idiagnl_keygen,
+ .oo_attrs2str = _idiagnl_attrs2str,
+ .oo_id_attrs = (IDIAGNL_ATTR_FAMILY |
+ IDIAGNL_ATTR_SRC |
+ IDIAGNL_ATTR_DST |
+ IDIAGNL_ATTR_SPORT |
+ IDIAGNL_ATTR_DPORT),
};
/** @endcond */
diff --git a/lib/idiag/idiag_req_obj.c b/lib/idiag/idiag_req_obj.c
index d9dab8e8..c825e403 100644
--- a/lib/idiag/idiag_req_obj.c
+++ b/lib/idiag/idiag_req_obj.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/idiag/idiagnl_req_obj.c Inet Diag Request Object
*
@@ -68,7 +69,7 @@ uint32_t idiagnl_req_get_ifindex(const struct idiagnl_req *req)
void idiagnl_req_set_ifindex(struct idiagnl_req *req, uint32_t ifindex)
{
- req->idiag_states = ifindex;
+ req->idiag_ifindex = ifindex;
}
uint32_t idiagnl_req_get_states(const struct idiagnl_req *req)
diff --git a/lib/idiag/idiag_vegasinfo_obj.c b/lib/idiag/idiag_vegasinfo_obj.c
index 5279e832..9a8f9935 100644
--- a/lib/idiag/idiag_vegasinfo_obj.c
+++ b/lib/idiag/idiag_vegasinfo_obj.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/idiag/idiagnl_vegasinfo_obj.c Inet Diag TCP Vegas Info Object
*
@@ -83,22 +84,25 @@ void idiagnl_vegasinfo_set_minrtt(struct idiagnl_vegasinfo *vinfo, uint32_t
}
/** @} */
-static int idiagnl_vegasinfo_clone(struct nl_object *_dst,
- struct nl_object *_src)
+/** @cond SKIP */
+static uint64_t idiagnl_vegasinfo_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
- struct idiagnl_vegasinfo *dst = (struct idiagnl_vegasinfo *) _dst;
- struct idiagnl_vegasinfo *src = (struct idiagnl_vegasinfo *) _src;
-
- memcpy(dst, src, sizeof(struct idiagnl_vegasinfo));
-
- return 0;
+ struct idiagnl_vegasinfo *a = (struct idiagnl_vegasinfo *) _a;
+ struct idiagnl_vegasinfo *b = (struct idiagnl_vegasinfo *) _b;
+
+ /* vegasinfo is a very simple object. It has no attribe flags (ce_mask),
+ * hence compare just returns 0 or 1, not a bit mask of attributes. */
+ return a->tcpv_enabled != b->tcpv_enabled ||
+ a->tcpv_rttcnt != b->tcpv_rttcnt ||
+ a->tcpv_rtt != b->tcpv_rtt ||
+ a->tcpv_minrtt != b->tcpv_minrtt;
}
-/** @cond SKIP */
struct nl_object_ops idiagnl_vegasinfo_obj_ops = {
.oo_name = "idiag/idiag_vegasinfo",
.oo_size = sizeof(struct idiagnl_vegasinfo),
- .oo_clone = idiagnl_vegasinfo_clone,
+ .oo_compare = idiagnl_vegasinfo_compare,
};
/** @endcond */
/** @} */
diff --git a/lib/mpls.c b/lib/mpls.c
new file mode 100644
index 00000000..6d0e493b
--- /dev/null
+++ b/lib/mpls.c
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * Adapted from mpls_ntop and mpls_pton copied from iproute2,
+ * lib/mpls_ntop.c and lib/mpls_pton.c
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <netlink/netlink-compat.h>
+#include <netlink-private/route/mpls.h>
+#include <linux-private/linux/mpls.h>
+
+static const char *mpls_ntop1(const struct mpls_label *addr,
+ char *buf, size_t buflen)
+{
+ size_t destlen = buflen;
+ char *dest = buf;
+ int count = 0;
+
+ while (1) {
+ uint32_t entry = ntohl(addr[count++].entry);
+ uint32_t label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
+ int len = snprintf(dest, destlen, "%u", label);
+
+ if (len >= destlen)
+ break;
+
+ /* Is this the end? */
+ if (entry & MPLS_LS_S_MASK)
+ return buf;
+
+ dest += len;
+ destlen -= len;
+ if (destlen) {
+ *dest = '/';
+ dest++;
+ destlen--;
+ }
+ }
+ errno = E2BIG;
+
+ return NULL;
+}
+
+const char *mpls_ntop(int af, const void *addr, char *buf, size_t buflen)
+{
+ switch(af) {
+ case AF_MPLS:
+ errno = 0;
+ return mpls_ntop1((struct mpls_label *)addr, buf, buflen);
+ }
+
+ errno = EINVAL;
+ return NULL;
+}
+
+static int mpls_pton1(const char *name, struct mpls_label *addr,
+ unsigned int maxlabels)
+{
+ char *endp;
+ unsigned count;
+
+ for (count = 0; count < maxlabels; count++) {
+ unsigned long label;
+
+ label = strtoul(name, &endp, 0);
+ /* Fail when the label value is out or range */
+ if (label >= (1 << 20))
+ return 0;
+
+ if (endp == name) /* no digits */
+ return 0;
+
+ addr->entry = htonl(label << MPLS_LS_LABEL_SHIFT);
+ if (*endp == '\0') {
+ addr->entry |= htonl(1 << MPLS_LS_S_SHIFT);
+ return (count + 1) * sizeof(struct mpls_label);
+ }
+
+ /* Bad character in the address */
+ if (*endp != '/')
+ return 0;
+
+ name = endp + 1;
+ addr += 1;
+ }
+
+ /* The address was too long */
+ return 0;
+}
+
+int mpls_pton(int af, const char *src, void *addr, size_t alen)
+{
+ unsigned int maxlabels = alen / sizeof(struct mpls_label);
+ int err;
+
+ switch(af) {
+ case AF_MPLS:
+ errno = 0;
+ err = mpls_pton1(src, (struct mpls_label *)addr, maxlabels);
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ err = -1;
+ }
+
+ return err;
+}
diff --git a/lib/msg.c b/lib/msg.c
index 01e533dc..c08b3a40 100644
--- a/lib/msg.c
+++ b/lib/msg.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/msg.c Netlink Messages Interface
*
@@ -27,6 +28,7 @@
*/
#include <netlink-private/netlink.h>
+#include <netlink-private/utils.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/cache.h>
@@ -211,7 +213,7 @@ struct nlmsghdr *nlmsg_next(struct nlmsghdr *nlh, int *remaining)
* See nla_parse()
*/
int nlmsg_parse(struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
- int maxtype, struct nla_policy *policy)
+ int maxtype, const struct nla_policy *policy)
{
if (!nlmsg_valid_hdr(nlh, hdrlen))
return -NLE_MSG_TOOSHORT;
@@ -242,7 +244,7 @@ struct nlattr *nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
* @arg policy validation policy
*/
int nlmsg_validate(struct nlmsghdr *nlh, int hdrlen, int maxtype,
- struct nla_policy *policy)
+ const struct nla_policy *policy)
{
if (!nlmsg_valid_hdr(nlh, hdrlen))
return -NLE_MSG_TOOSHORT;
@@ -349,6 +351,8 @@ struct nl_msg *nlmsg_alloc_simple(int nlmsgtype, int flags)
struct nlmsghdr nlh = {
.nlmsg_type = nlmsgtype,
.nlmsg_flags = flags,
+ .nlmsg_seq = NL_AUTO_SEQ,
+ .nlmsg_pid = NL_AUTO_PID,
};
msg = nlmsg_inherit(&nlh);
@@ -406,7 +410,7 @@ struct nl_msg *nlmsg_convert(struct nlmsghdr *hdr)
*/
void *nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
{
- void *buf = n->nm_nlh;
+ char *buf = (char *) n->nm_nlh;
size_t nlmsg_len = n->nm_nlh->nlmsg_len;
size_t tlen;
@@ -640,10 +644,10 @@ struct ucred *nlmsg_get_creds(struct nl_msg *msg)
*/
static const struct trans_tbl nl_msgtypes[] = {
- __ADD(NLMSG_NOOP,NOOP)
- __ADD(NLMSG_ERROR,ERROR)
- __ADD(NLMSG_DONE,DONE)
- __ADD(NLMSG_OVERRUN,OVERRUN)
+ __ADD(NLMSG_NOOP,NOOP),
+ __ADD(NLMSG_ERROR,ERROR),
+ __ADD(NLMSG_DONE,DONE),
+ __ADD(NLMSG_OVERRUN,OVERRUN),
};
char *nl_nlmsgtype2str(int type, char *buf, size_t size)
@@ -834,7 +838,7 @@ static void print_genl_hdr(FILE *ofd, void *start)
static void *print_genl_msg(struct nl_msg *msg, FILE *ofd, struct nlmsghdr *hdr,
struct nl_cache_ops *ops, int *payloadlen)
{
- void *data = nlmsg_data(hdr);
+ char *data = nlmsg_data(hdr);
if (*payloadlen < GENL_HDRLEN)
return data;
@@ -897,7 +901,7 @@ static void dump_attrs(FILE *ofd, struct nlattr *attrs, int attrlen,
prefix_line(ofd, prefix);
fprintf(ofd, " [PADDING] %d octets\n",
padlen);
- dump_hex(ofd, nla_data(nla) + alen,
+ dump_hex(ofd, (char *) nla_data(nla) + alen,
padlen, prefix);
}
}
@@ -916,11 +920,10 @@ static void dump_error_msg(struct nl_msg *msg, FILE *ofd)
fprintf(ofd, " [ERRORMSG] %zu octets\n", sizeof(*err));
if (nlmsg_len(hdr) >= sizeof(*err)) {
- char buf[256];
struct nl_msg *errmsg;
fprintf(ofd, " .error = %d \"%s\"\n", err->error,
- strerror_r(-err->error, buf, sizeof(buf)));
+ nl_strerror_l(-err->error));
fprintf(ofd, " [ORIGINAL MESSAGE] %zu octets\n", sizeof(*hdr));
errmsg = nlmsg_inherit(&err->msg);
diff --git a/lib/netfilter/ct.c b/lib/netfilter/ct.c
index 36a83dbe..98aaafc2 100644
--- a/lib/netfilter/ct.c
+++ b/lib/netfilter/ct.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/ct.c Conntrack
*
@@ -27,28 +28,10 @@
#include <netlink/attr.h>
#include <netlink/netfilter/nfnl.h>
#include <netlink/netfilter/ct.h>
+#include <netlink-private/utils.h>
static struct nl_cache_ops nfnl_ct_ops;
-#if __BYTE_ORDER == __BIG_ENDIAN
-static uint64_t ntohll(uint64_t x)
-{
- return x;
-}
-static uint64_t htonll(uint64_t x)
-{
- return x;
-}
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-static uint64_t ntohll(uint64_t x)
-{
- return bswap_64(x);
-}
-static uint64_t htonll(uint64_t x)
-{
- return bswap_64(x);
-}
-#endif
static struct nla_policy ct_policy[CTA_MAX+1] = {
[CTA_TUPLE_ORIG] = { .type = NLA_NESTED },
@@ -122,7 +105,7 @@ static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr)
struct nl_addr *addr;
int err;
- err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
+ err = nla_parse_nested(tb, CTA_IP_MAX, attr, ct_ip_policy);
if (err < 0)
goto errout;
@@ -421,6 +404,13 @@ static int ct_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
return err;
}
+/**
+ * Send nfnl ct dump request
+ * @arg sk Netlink socket.
+ *
+ * @return 0 on success or a negative error code. Due to a bug, this function
+ * returns the number of bytes sent. Treat any non-negative number as success.
+ */
int nfnl_ct_dump_request(struct nl_sock *sk)
{
return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET,
diff --git a/lib/netfilter/ct_obj.c b/lib/netfilter/ct_obj.c
index 61b6a31b..08aa9459 100644
--- a/lib/netfilter/ct_obj.c
+++ b/lib/netfilter/ct_obj.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/ct_obj.c Conntrack Object
*
@@ -297,12 +298,12 @@ static void ct_dump_stats(struct nl_object *a, struct nl_dump_params *p)
}
}
-static int ct_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint64_t ct_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct nfnl_ct *a = (struct nfnl_ct *) _a;
struct nfnl_ct *b = (struct nfnl_ct *) _b;
- int diff = 0;
+ uint64_t diff = 0;
#define CT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, CT_ATTR_##ATTR, a, b, EXPR)
#define CT_DIFF_VAL(ATTR, FIELD) CT_DIFF(ATTR, a->FIELD != b->FIELD)
@@ -351,32 +352,32 @@ static int ct_compare(struct nl_object *_a, struct nl_object *_b,
}
static const struct trans_tbl ct_attrs[] = {
- __ADD(CT_ATTR_FAMILY, family)
- __ADD(CT_ATTR_PROTO, proto)
- __ADD(CT_ATTR_TCP_STATE, tcpstate)
- __ADD(CT_ATTR_STATUS, status)
- __ADD(CT_ATTR_TIMEOUT, timeout)
- __ADD(CT_ATTR_MARK, mark)
- __ADD(CT_ATTR_USE, use)
- __ADD(CT_ATTR_ID, id)
- __ADD(CT_ATTR_ORIG_SRC, origsrc)
- __ADD(CT_ATTR_ORIG_DST, origdst)
- __ADD(CT_ATTR_ORIG_SRC_PORT, origsrcport)
- __ADD(CT_ATTR_ORIG_DST_PORT, origdstport)
- __ADD(CT_ATTR_ORIG_ICMP_ID, origicmpid)
- __ADD(CT_ATTR_ORIG_ICMP_TYPE, origicmptype)
- __ADD(CT_ATTR_ORIG_ICMP_CODE, origicmpcode)
- __ADD(CT_ATTR_ORIG_PACKETS, origpackets)
- __ADD(CT_ATTR_ORIG_BYTES, origbytes)
- __ADD(CT_ATTR_REPL_SRC, replysrc)
- __ADD(CT_ATTR_REPL_DST, replydst)
- __ADD(CT_ATTR_REPL_SRC_PORT, replysrcport)
- __ADD(CT_ATTR_REPL_DST_PORT, replydstport)
- __ADD(CT_ATTR_REPL_ICMP_ID, replyicmpid)
- __ADD(CT_ATTR_REPL_ICMP_TYPE, replyicmptype)
- __ADD(CT_ATTR_REPL_ICMP_CODE, replyicmpcode)
- __ADD(CT_ATTR_REPL_PACKETS, replypackets)
- __ADD(CT_ATTR_REPL_BYTES, replybytes)
+ __ADD(CT_ATTR_FAMILY, family),
+ __ADD(CT_ATTR_PROTO, proto),
+ __ADD(CT_ATTR_TCP_STATE, tcpstate),
+ __ADD(CT_ATTR_STATUS, status),
+ __ADD(CT_ATTR_TIMEOUT, timeout),
+ __ADD(CT_ATTR_MARK, mark),
+ __ADD(CT_ATTR_USE, use),
+ __ADD(CT_ATTR_ID, id),
+ __ADD(CT_ATTR_ORIG_SRC, origsrc),
+ __ADD(CT_ATTR_ORIG_DST, origdst),
+ __ADD(CT_ATTR_ORIG_SRC_PORT, origsrcport),
+ __ADD(CT_ATTR_ORIG_DST_PORT, origdstport),
+ __ADD(CT_ATTR_ORIG_ICMP_ID, origicmpid),
+ __ADD(CT_ATTR_ORIG_ICMP_TYPE, origicmptype),
+ __ADD(CT_ATTR_ORIG_ICMP_CODE, origicmpcode),
+ __ADD(CT_ATTR_ORIG_PACKETS, origpackets),
+ __ADD(CT_ATTR_ORIG_BYTES, origbytes),
+ __ADD(CT_ATTR_REPL_SRC, replysrc),
+ __ADD(CT_ATTR_REPL_DST, replydst),
+ __ADD(CT_ATTR_REPL_SRC_PORT, replysrcport),
+ __ADD(CT_ATTR_REPL_DST_PORT, replydstport),
+ __ADD(CT_ATTR_REPL_ICMP_ID, replyicmpid),
+ __ADD(CT_ATTR_REPL_ICMP_TYPE, replyicmptype),
+ __ADD(CT_ATTR_REPL_ICMP_CODE, replyicmpcode),
+ __ADD(CT_ATTR_REPL_PACKETS, replypackets),
+ __ADD(CT_ATTR_REPL_BYTES, replybytes),
};
static char *ct_attrs2str(int attrs, char *buf, size_t len)
@@ -458,16 +459,16 @@ uint8_t nfnl_ct_get_tcp_state(const struct nfnl_ct *ct)
}
static const struct trans_tbl tcp_states[] = {
- __ADD(TCP_CONNTRACK_NONE,NONE)
- __ADD(TCP_CONNTRACK_SYN_SENT,SYN_SENT)
- __ADD(TCP_CONNTRACK_SYN_RECV,SYN_RECV)
- __ADD(TCP_CONNTRACK_ESTABLISHED,ESTABLISHED)
- __ADD(TCP_CONNTRACK_FIN_WAIT,FIN_WAIT)
- __ADD(TCP_CONNTRACK_CLOSE_WAIT,CLOSE_WAIT)
- __ADD(TCP_CONNTRACK_LAST_ACK,LAST_ACK)
- __ADD(TCP_CONNTRACK_TIME_WAIT,TIME_WAIT)
- __ADD(TCP_CONNTRACK_CLOSE,CLOSE)
- __ADD(TCP_CONNTRACK_LISTEN,LISTEN)
+ __ADD(TCP_CONNTRACK_NONE,NONE),
+ __ADD(TCP_CONNTRACK_SYN_SENT,SYN_SENT),
+ __ADD(TCP_CONNTRACK_SYN_RECV,SYN_RECV),
+ __ADD(TCP_CONNTRACK_ESTABLISHED,ESTABLISHED),
+ __ADD(TCP_CONNTRACK_FIN_WAIT,FIN_WAIT),
+ __ADD(TCP_CONNTRACK_CLOSE_WAIT,CLOSE_WAIT),
+ __ADD(TCP_CONNTRACK_LAST_ACK,LAST_ACK),
+ __ADD(TCP_CONNTRACK_TIME_WAIT,TIME_WAIT),
+ __ADD(TCP_CONNTRACK_CLOSE,CLOSE),
+ __ADD(TCP_CONNTRACK_LISTEN,LISTEN),
};
char *nfnl_ct_tcp_state2str(uint8_t state, char *buf, size_t len)
@@ -477,7 +478,7 @@ char *nfnl_ct_tcp_state2str(uint8_t state, char *buf, size_t len)
int nfnl_ct_str2tcp_state(const char *name)
{
- return __str2type(name, tcp_states, ARRAY_SIZE(tcp_states));
+ return __str2type(name, tcp_states, ARRAY_SIZE(tcp_states));
}
void nfnl_ct_set_status(struct nfnl_ct *ct, uint32_t status)
@@ -505,17 +506,17 @@ uint32_t nfnl_ct_get_status(const struct nfnl_ct *ct)
}
static const struct trans_tbl status_flags[] = {
- __ADD(IPS_EXPECTED, expected)
- __ADD(IPS_SEEN_REPLY, seen_reply)
- __ADD(IPS_ASSURED, assured)
- __ADD(IPS_CONFIRMED, confirmed)
- __ADD(IPS_SRC_NAT, snat)
- __ADD(IPS_DST_NAT, dnat)
- __ADD(IPS_SEQ_ADJUST, seqadjust)
- __ADD(IPS_SRC_NAT_DONE, snat_done)
- __ADD(IPS_DST_NAT_DONE, dnat_done)
- __ADD(IPS_DYING, dying)
- __ADD(IPS_FIXED_TIMEOUT, fixed_timeout)
+ __ADD(IPS_EXPECTED, expected),
+ __ADD(IPS_SEEN_REPLY, seen_reply),
+ __ADD(IPS_ASSURED, assured),
+ __ADD(IPS_CONFIRMED, confirmed),
+ __ADD(IPS_SRC_NAT, snat),
+ __ADD(IPS_DST_NAT, dnat),
+ __ADD(IPS_SEQ_ADJUST, seqadjust),
+ __ADD(IPS_SRC_NAT_DONE, snat_done),
+ __ADD(IPS_DST_NAT_DONE, dnat_done),
+ __ADD(IPS_DYING, dying),
+ __ADD(IPS_FIXED_TIMEOUT, fixed_timeout),
};
char * nfnl_ct_status2str(int flags, char *buf, size_t len)
diff --git a/lib/netfilter/exp.c b/lib/netfilter/exp.c
index 9cfdd2bf..d4758614 100644
--- a/lib/netfilter/exp.c
+++ b/lib/netfilter/exp.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/exp.c Conntrack Expectation
*
@@ -305,6 +306,13 @@ static int exp_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
return err;
}
+/**
+ * Send nfnl exp dump request
+ * @arg sk Netlink socket.
+ *
+ * @return 0 on success or a negative error code. Due to a bug, this function
+ * returns the number of bytes sent. Treat any non-negative number as success.
+ */
int nfnl_exp_dump_request(struct nl_sock *sk)
{
return nfnl_send_simple(sk, NFNL_SUBSYS_CTNETLINK_EXP, IPCTNL_MSG_EXP_GET,
@@ -345,15 +353,16 @@ static int nfnl_exp_build_tuple(struct nl_msg *msg, const struct nfnl_exp *exp,
struct nlattr *tuple, *ip, *proto;
struct nl_addr *addr;
int family;
+ int type;
family = nfnl_exp_get_family(exp);
- int type = exp_get_tuple_attr(cta);
+ type = exp_get_tuple_attr(cta);
- if (cta == CTA_EXPECT_NAT)
- tuple = nla_nest_start(msg, CTA_EXPECT_NAT_TUPLE);
- else
- tuple = nla_nest_start(msg, cta);
+ if (cta == CTA_EXPECT_NAT)
+ tuple = nla_nest_start(msg, CTA_EXPECT_NAT_TUPLE);
+ else
+ tuple = nla_nest_start(msg, cta);
if (!tuple)
goto nla_put_failure;
@@ -483,6 +492,8 @@ static int nfnl_exp_build_message(const struct nfnl_exp *exp, int cmd, int flags
return 0;
nla_put_failure:
+ err = -NLE_NOMEM;
+
err_out:
nlmsg_free(msg);
return err;
diff --git a/lib/netfilter/exp_obj.c b/lib/netfilter/exp_obj.c
index 69b4dd31..8cd59eed 100644
--- a/lib/netfilter/exp_obj.c
+++ b/lib/netfilter/exp_obj.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/exp_obj.c Conntrack Expectation Object
*
@@ -132,7 +133,7 @@ static int exp_clone(struct nl_object *_dst, struct nl_object *_src)
dst->exp_mask.dst = addr;
}
- // NAT
+ // NAT
if (src->exp_nat.src) {
addr = nl_addr_clone(src->exp_nat.src);
if (!addr)
@@ -200,7 +201,7 @@ static void exp_dump_tuples(struct nfnl_exp *exp, struct nl_dump_params *p)
if (nfnl_exp_test_dst(exp, i))
tuple_dst = nfnl_exp_get_dst(exp, i);
- // Don't have tests for individual ports/types/codes/ids,
+ // Don't have tests for individual ports/types/codes/ids,
if (nfnl_exp_test_l4protonum(exp, i)) {
nl_dump(p, "%s ",
nl_ip_proto2str(nfnl_exp_get_l4protonum(exp, i), buf, sizeof(buf)));
@@ -286,27 +287,27 @@ static int exp_cmp_l4proto_ports (union nfnl_exp_protodata *a, union nfnl_exp_pr
// Must return 0 for match, 1 for mismatch
int d = 0;
d = ( (a->port.src != b->port.src) ||
- (a->port.dst != b->port.dst) );
+ (a->port.dst != b->port.dst) );
return d;
}
static int exp_cmp_l4proto_icmp (union nfnl_exp_protodata *a, union nfnl_exp_protodata *b) {
- // Must return 0 for match, 1 for mismatch
+ // Must return 0 for match, 1 for mismatch
int d = 0;
d = ( (a->icmp.code != b->icmp.code) ||
- (a->icmp.type != b->icmp.type) ||
- (a->icmp.id != b->icmp.id) );
+ (a->icmp.type != b->icmp.type) ||
+ (a->icmp.id != b->icmp.id) );
return d;
}
-static int exp_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint64_t exp_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct nfnl_exp *a = (struct nfnl_exp *) _a;
struct nfnl_exp *b = (struct nfnl_exp *) _b;
- int diff = 0;
+ uint64_t diff = 0;
#define EXP_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, EXP_ATTR_##ATTR, a, b, EXPR)
#define EXP_DIFF_VAL(ATTR, FIELD) EXP_DIFF(ATTR, a->FIELD != b->FIELD)
@@ -367,35 +368,35 @@ static int exp_compare(struct nl_object *_a, struct nl_object *_b,
// CLI arguments?
static const struct trans_tbl exp_attrs[] = {
- __ADD(EXP_ATTR_FAMILY, family)
- __ADD(EXP_ATTR_TIMEOUT, timeout)
- __ADD(EXP_ATTR_ID, id)
- __ADD(EXP_ATTR_HELPER_NAME, helpername)
- __ADD(EXP_ATTR_ZONE, zone)
- __ADD(EXP_ATTR_CLASS, class)
- __ADD(EXP_ATTR_FLAGS, flags)
- __ADD(EXP_ATTR_FN, function)
- __ADD(EXP_ATTR_EXPECT_IP_SRC, expectipsrc)
- __ADD(EXP_ATTR_EXPECT_IP_DST, expectipdst)
- __ADD(EXP_ATTR_EXPECT_L4PROTO_NUM, expectprotonum)
- __ADD(EXP_ATTR_EXPECT_L4PROTO_PORTS, expectports)
- __ADD(EXP_ATTR_EXPECT_L4PROTO_ICMP, expecticmp)
- __ADD(EXP_ATTR_MASTER_IP_SRC, masteripsrc)
- __ADD(EXP_ATTR_MASTER_IP_DST, masteripdst)
- __ADD(EXP_ATTR_MASTER_L4PROTO_NUM, masterprotonum)
- __ADD(EXP_ATTR_MASTER_L4PROTO_PORTS, masterports)
- __ADD(EXP_ATTR_MASTER_L4PROTO_ICMP, mastericmp)
- __ADD(EXP_ATTR_MASK_IP_SRC, maskipsrc)
- __ADD(EXP_ATTR_MASK_IP_DST, maskipdst)
- __ADD(EXP_ATTR_MASK_L4PROTO_NUM, maskprotonum)
- __ADD(EXP_ATTR_MASK_L4PROTO_PORTS, maskports)
- __ADD(EXP_ATTR_MASK_L4PROTO_ICMP, maskicmp)
- __ADD(EXP_ATTR_NAT_IP_SRC, natipsrc)
- __ADD(EXP_ATTR_NAT_IP_DST, natipdst)
- __ADD(EXP_ATTR_NAT_L4PROTO_NUM, natprotonum)
- __ADD(EXP_ATTR_NAT_L4PROTO_PORTS, natports)
- __ADD(EXP_ATTR_NAT_L4PROTO_ICMP, naticmp)
- __ADD(EXP_ATTR_NAT_DIR, natdir)
+ __ADD(EXP_ATTR_FAMILY, family),
+ __ADD(EXP_ATTR_TIMEOUT, timeout),
+ __ADD(EXP_ATTR_ID, id),
+ __ADD(EXP_ATTR_HELPER_NAME, helpername),
+ __ADD(EXP_ATTR_ZONE, zone),
+ __ADD(EXP_ATTR_CLASS, class),
+ __ADD(EXP_ATTR_FLAGS, flags),
+ __ADD(EXP_ATTR_FN, function),
+ __ADD(EXP_ATTR_EXPECT_IP_SRC, expectipsrc),
+ __ADD(EXP_ATTR_EXPECT_IP_DST, expectipdst),
+ __ADD(EXP_ATTR_EXPECT_L4PROTO_NUM, expectprotonum),
+ __ADD(EXP_ATTR_EXPECT_L4PROTO_PORTS, expectports),
+ __ADD(EXP_ATTR_EXPECT_L4PROTO_ICMP, expecticmp),
+ __ADD(EXP_ATTR_MASTER_IP_SRC, masteripsrc),
+ __ADD(EXP_ATTR_MASTER_IP_DST, masteripdst),
+ __ADD(EXP_ATTR_MASTER_L4PROTO_NUM, masterprotonum),
+ __ADD(EXP_ATTR_MASTER_L4PROTO_PORTS, masterports),
+ __ADD(EXP_ATTR_MASTER_L4PROTO_ICMP, mastericmp),
+ __ADD(EXP_ATTR_MASK_IP_SRC, maskipsrc),
+ __ADD(EXP_ATTR_MASK_IP_DST, maskipdst),
+ __ADD(EXP_ATTR_MASK_L4PROTO_NUM, maskprotonum),
+ __ADD(EXP_ATTR_MASK_L4PROTO_PORTS, maskports),
+ __ADD(EXP_ATTR_MASK_L4PROTO_ICMP, maskicmp),
+ __ADD(EXP_ATTR_NAT_IP_SRC, natipsrc),
+ __ADD(EXP_ATTR_NAT_IP_DST, natipdst),
+ __ADD(EXP_ATTR_NAT_L4PROTO_NUM, natprotonum),
+ __ADD(EXP_ATTR_NAT_L4PROTO_PORTS, natports),
+ __ADD(EXP_ATTR_NAT_L4PROTO_ICMP, naticmp),
+ __ADD(EXP_ATTR_NAT_DIR, natdir),
};
static char *exp_attrs2str(int attrs, char *buf, size_t len)
@@ -467,9 +468,9 @@ uint32_t nfnl_exp_get_flags(const struct nfnl_exp *exp)
}
static const struct trans_tbl flag_table[] = {
- __ADD(IPS_EXPECTED, expected)
- __ADD(IPS_SEEN_REPLY, seen_reply)
- __ADD(IPS_ASSURED, assured)
+ __ADD(IPS_EXPECTED, expected),
+ __ADD(IPS_SEEN_REPLY, seen_reply),
+ __ADD(IPS_ASSURED, assured),
};
char * nfnl_exp_flags2str(int flags, char *buf, size_t len)
diff --git a/lib/netfilter/log.c b/lib/netfilter/log.c
index 1bab9b6b..17618085 100644
--- a/lib/netfilter/log.c
+++ b/lib/netfilter/log.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/log.c Netfilter Log
*
diff --git a/lib/netfilter/log_msg.c b/lib/netfilter/log_msg.c
index 5ffdaf80..e1f92eb2 100644
--- a/lib/netfilter/log_msg.c
+++ b/lib/netfilter/log_msg.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/log_msg.c Netfilter Log Message
*
@@ -26,19 +27,7 @@
#include <netlink/attr.h>
#include <netlink/netfilter/nfnl.h>
#include <netlink/netfilter/log_msg.h>
-#include <byteswap.h>
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-static uint64_t ntohll(uint64_t x)
-{
- return x;
-}
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-static uint64_t ntohll(uint64_t x)
-{
- return bswap_64(x);
-}
-#endif
+#include <netlink-private/utils.h>
static struct nla_policy log_msg_policy[NFULA_MAX+1] = {
[NFULA_PACKET_HDR] = {
diff --git a/lib/netfilter/log_msg_obj.c b/lib/netfilter/log_msg_obj.c
index 57db9d47..90b7bc93 100644
--- a/lib/netfilter/log_msg_obj.c
+++ b/lib/netfilter/log_msg_obj.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/log_msg_obj.c Netfilter Log Object
*
diff --git a/lib/netfilter/log_obj.c b/lib/netfilter/log_obj.c
index 2b114142..a33ef9f2 100644
--- a/lib/netfilter/log_obj.c
+++ b/lib/netfilter/log_obj.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/log_obj.c Netfilter Log Object
*
@@ -57,9 +58,9 @@ static void nfnl_log_dump(struct nl_object *a, struct nl_dump_params *p)
}
static const struct trans_tbl copy_modes[] = {
- __ADD(NFNL_LOG_COPY_NONE, none)
- __ADD(NFNL_LOG_COPY_META, meta)
- __ADD(NFNL_LOG_COPY_PACKET, packet)
+ __ADD(NFNL_LOG_COPY_NONE, none),
+ __ADD(NFNL_LOG_COPY_META, meta),
+ __ADD(NFNL_LOG_COPY_PACKET, packet),
};
char *nfnl_log_copy_mode2str(enum nfnl_log_copy_mode copy_mode, char *buf,
@@ -69,7 +70,7 @@ char *nfnl_log_copy_mode2str(enum nfnl_log_copy_mode copy_mode, char *buf,
ARRAY_SIZE(copy_modes));
}
-enum nfnl_log_copy_mode nfnl_log_str2copy_mode(const char *name)
+int nfnl_log_str2copy_mode(const char *name)
{
return __str2type(name, copy_modes, ARRAY_SIZE(copy_modes));
}
@@ -215,8 +216,8 @@ void nfnl_log_unset_flags(struct nfnl_log *log, unsigned int flags)
}
static const struct trans_tbl log_flags[] = {
- __ADD(NFNL_LOG_FLAG_SEQ, seq)
- __ADD(NFNL_LOG_FLAG_SEQ_GLOBAL, seq_global)
+ __ADD(NFNL_LOG_FLAG_SEQ, seq),
+ __ADD(NFNL_LOG_FLAG_SEQ_GLOBAL, seq_global),
};
char *nfnl_log_flags2str(unsigned int flags, char *buf, size_t len)
@@ -229,12 +230,12 @@ unsigned int nfnl_log_str2flags(const char *name)
return __str2flags(name, log_flags, ARRAY_SIZE(log_flags));
}
-static int nfnl_log_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint64_t nfnl_log_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct nfnl_log *a = (struct nfnl_log *) _a;
struct nfnl_log *b = (struct nfnl_log *) _b;
- int diff = 0;
+ uint64_t diff = 0;
#define NFNL_LOG_DIFF(ATTR, EXPR) \
ATTR_DIFF(attrs, LOG_ATTR_##ATTR, a, b, EXPR)
@@ -255,12 +256,12 @@ static int nfnl_log_compare(struct nl_object *_a, struct nl_object *_b,
}
static const struct trans_tbl nfnl_log_attrs[] = {
- __ADD(LOG_ATTR_GROUP, group)
- __ADD(LOG_ATTR_COPY_MODE, copy_mode)
- __ADD(LOG_ATTR_COPY_RANGE, copy_range)
- __ADD(LOG_ATTR_FLUSH_TIMEOUT, flush_timeout)
- __ADD(LOG_ATTR_ALLOC_SIZE, alloc_size)
- __ADD(LOG_ATTR_QUEUE_THRESHOLD, queue_threshold)
+ __ADD(LOG_ATTR_GROUP, group),
+ __ADD(LOG_ATTR_COPY_MODE, copy_mode),
+ __ADD(LOG_ATTR_COPY_RANGE, copy_range),
+ __ADD(LOG_ATTR_FLUSH_TIMEOUT, flush_timeout),
+ __ADD(LOG_ATTR_ALLOC_SIZE, alloc_size),
+ __ADD(LOG_ATTR_QUEUE_THRESHOLD, queue_threshold),
};
static char *nfnl_log_attrs2str(int attrs, char *buf, size_t len)
diff --git a/lib/netfilter/netfilter.c b/lib/netfilter/netfilter.c
index 0062994f..dba435de 100644
--- a/lib/netfilter/netfilter.c
+++ b/lib/netfilter/netfilter.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/netfilter.c Netfilter Generic Functions
*
@@ -14,12 +15,12 @@
#include <linux/netfilter.h>
static const struct trans_tbl nfnl_verdicts[] = {
- __ADD(NF_DROP, NF_DROP)
- __ADD(NF_ACCEPT, NF_ACCEPT)
- __ADD(NF_STOLEN, NF_STOLEN)
- __ADD(NF_QUEUE, NF_QUEUE)
- __ADD(NF_REPEAT, NF_REPEAT)
- __ADD(NF_STOP, NF_STOP)
+ __ADD(NF_DROP, NF_DROP),
+ __ADD(NF_ACCEPT, NF_ACCEPT),
+ __ADD(NF_STOLEN, NF_STOLEN),
+ __ADD(NF_QUEUE, NF_QUEUE),
+ __ADD(NF_REPEAT, NF_REPEAT),
+ __ADD(NF_STOP, NF_STOP),
};
char *nfnl_verdict2str(unsigned int verdict, char *buf, size_t len)
@@ -34,11 +35,11 @@ unsigned int nfnl_str2verdict(const char *name)
}
static const struct trans_tbl nfnl_inet_hooks[] = {
- __ADD(NF_INET_PRE_ROUTING, NF_INET_PREROUTING)
- __ADD(NF_INET_LOCAL_IN, NF_INET_LOCAL_IN)
- __ADD(NF_INET_FORWARD, NF_INET_FORWARD)
- __ADD(NF_INET_LOCAL_OUT, NF_INET_LOCAL_OUT)
- __ADD(NF_INET_POST_ROUTING, NF_INET_POST_ROUTING)
+ __ADD(NF_INET_PRE_ROUTING, NF_INET_PREROUTING),
+ __ADD(NF_INET_LOCAL_IN, NF_INET_LOCAL_IN),
+ __ADD(NF_INET_FORWARD, NF_INET_FORWARD),
+ __ADD(NF_INET_LOCAL_OUT, NF_INET_LOCAL_OUT),
+ __ADD(NF_INET_POST_ROUTING, NF_INET_POST_ROUTING),
};
char *nfnl_inet_hook2str(unsigned int hook, char *buf, size_t len)
diff --git a/lib/netfilter/nfnl.c b/lib/netfilter/nfnl.c
index f028a859..ac502fb4 100644
--- a/lib/netfilter/nfnl.c
+++ b/lib/netfilter/nfnl.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/nfnl.c Netfilter Netlink
*
@@ -65,6 +66,8 @@
#include <netlink/netlink.h>
#include <netlink/netfilter/nfnl.h>
+#include <linux/netfilter/nfnetlink.h>
+
/**
* @name Socket Creating
* @{
@@ -102,7 +105,8 @@ int nfnl_connect(struct nl_sock *sk)
* @arg family nfnetlink address family
* @arg res_id nfnetlink resource id
*
- * @return Newly allocated netlink message or NULL.
+ * @return 0 on success or a negative error code. Due to a bug, this function
+ * returns the number of bytes sent. Treat any non-negative number as success.
*/
int nfnl_send_simple(struct nl_sock *sk, uint8_t subsys_id, uint8_t type,
int flags, uint8_t family, uint16_t res_id)
diff --git a/lib/netfilter/queue.c b/lib/netfilter/queue.c
index 56556479..d20dee5e 100644
--- a/lib/netfilter/queue.c
+++ b/lib/netfilter/queue.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/queue.c Netfilter Queue
*
diff --git a/lib/netfilter/queue_msg.c b/lib/netfilter/queue_msg.c
index 33889233..68ed71e6 100644
--- a/lib/netfilter/queue_msg.c
+++ b/lib/netfilter/queue_msg.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/queue_msg.c Netfilter Queue Messages
*
@@ -24,22 +25,10 @@
#include <netlink/attr.h>
#include <netlink/netfilter/nfnl.h>
#include <netlink/netfilter/queue_msg.h>
-#include <byteswap.h>
+#include <netlink-private/utils.h>
static struct nl_cache_ops nfnl_queue_msg_ops;
-#if __BYTE_ORDER == __BIG_ENDIAN
-static uint64_t ntohll(uint64_t x)
-{
- return x;
-}
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
-static uint64_t ntohll(uint64_t x)
-{
- return bswap_64(x);
-}
-#endif
-
static struct nla_policy queue_policy[NFQA_MAX+1] = {
[NFQA_PACKET_HDR] = {
.minlen = sizeof(struct nfqnl_msg_packet_hdr),
diff --git a/lib/netfilter/queue_msg_obj.c b/lib/netfilter/queue_msg_obj.c
index 8085f1b3..1e89cc49 100644
--- a/lib/netfilter/queue_msg_obj.c
+++ b/lib/netfilter/queue_msg_obj.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/queue_msg_obj.c Netfilter Queue Message Object
*
@@ -405,12 +406,15 @@ const uint8_t *nfnl_queue_msg_get_hwaddr(const struct nfnl_queue_msg *msg,
int nfnl_queue_msg_set_payload(struct nfnl_queue_msg *msg, uint8_t *payload,
int len)
{
- free(msg->queue_msg_payload);
- msg->queue_msg_payload = malloc(len);
- if (!msg->queue_msg_payload)
+ void *new_payload = malloc(len);
+
+ if (new_payload == NULL)
return -NLE_NOMEM;
+ memcpy(new_payload, payload, len);
+
+ free(msg->queue_msg_payload);
- memcpy(msg->queue_msg_payload, payload, len);
+ msg->queue_msg_payload = new_payload;
msg->queue_msg_payload_len = len;
msg->ce_mask |= QUEUE_MSG_ATTR_PAYLOAD;
return 0;
@@ -455,20 +459,20 @@ unsigned int nfnl_queue_msg_get_verdict(const struct nfnl_queue_msg *msg)
}
static const struct trans_tbl nfnl_queue_msg_attrs[] = {
- __ADD(QUEUE_MSG_ATTR_GROUP, group)
- __ADD(QUEUE_MSG_ATTR_FAMILY, family)
- __ADD(QUEUE_MSG_ATTR_PACKETID, packetid)
- __ADD(QUEUE_MSG_ATTR_HWPROTO, hwproto)
- __ADD(QUEUE_MSG_ATTR_HOOK, hook)
- __ADD(QUEUE_MSG_ATTR_MARK, mark)
- __ADD(QUEUE_MSG_ATTR_TIMESTAMP, timestamp)
- __ADD(QUEUE_MSG_ATTR_INDEV, indev)
- __ADD(QUEUE_MSG_ATTR_OUTDEV, outdev)
- __ADD(QUEUE_MSG_ATTR_PHYSINDEV, physindev)
- __ADD(QUEUE_MSG_ATTR_PHYSOUTDEV, physoutdev)
- __ADD(QUEUE_MSG_ATTR_HWADDR, hwaddr)
- __ADD(QUEUE_MSG_ATTR_PAYLOAD, payload)
- __ADD(QUEUE_MSG_ATTR_VERDICT, verdict)
+ __ADD(QUEUE_MSG_ATTR_GROUP, group),
+ __ADD(QUEUE_MSG_ATTR_FAMILY, family),
+ __ADD(QUEUE_MSG_ATTR_PACKETID, packetid),
+ __ADD(QUEUE_MSG_ATTR_HWPROTO, hwproto),
+ __ADD(QUEUE_MSG_ATTR_HOOK, hook),
+ __ADD(QUEUE_MSG_ATTR_MARK, mark),
+ __ADD(QUEUE_MSG_ATTR_TIMESTAMP, timestamp),
+ __ADD(QUEUE_MSG_ATTR_INDEV, indev),
+ __ADD(QUEUE_MSG_ATTR_OUTDEV, outdev),
+ __ADD(QUEUE_MSG_ATTR_PHYSINDEV, physindev),
+ __ADD(QUEUE_MSG_ATTR_PHYSOUTDEV, physoutdev),
+ __ADD(QUEUE_MSG_ATTR_HWADDR, hwaddr),
+ __ADD(QUEUE_MSG_ATTR_PAYLOAD, payload),
+ __ADD(QUEUE_MSG_ATTR_VERDICT, verdict),
};
static char *nfnl_queue_msg_attrs2str(int attrs, char *buf, size_t len)
diff --git a/lib/netfilter/queue_obj.c b/lib/netfilter/queue_obj.c
index 5edcc684..690b26e3 100644
--- a/lib/netfilter/queue_obj.c
+++ b/lib/netfilter/queue_obj.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/netfilter/queue_obj.c Netfilter Queue
*
@@ -53,9 +54,9 @@ static void nfnl_queue_dump(struct nl_object *a, struct nl_dump_params *p)
}
static const struct trans_tbl copy_modes[] = {
- __ADD(NFNL_QUEUE_COPY_NONE, none)
- __ADD(NFNL_QUEUE_COPY_META, meta)
- __ADD(NFNL_QUEUE_COPY_PACKET, packet)
+ __ADD(NFNL_QUEUE_COPY_NONE, none),
+ __ADD(NFNL_QUEUE_COPY_META, meta),
+ __ADD(NFNL_QUEUE_COPY_PACKET, packet),
};
char *nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode copy_mode, char *buf,
@@ -65,7 +66,7 @@ char *nfnl_queue_copy_mode2str(enum nfnl_queue_copy_mode copy_mode, char *buf,
ARRAY_SIZE(copy_modes));
}
-enum nfnl_queue_copy_mode nfnl_queue_str2copy_mode(const char *name)
+int nfnl_queue_str2copy_mode(const char *name)
{
return __str2type(name, copy_modes, ARRAY_SIZE(copy_modes));
}
@@ -161,12 +162,12 @@ uint32_t nfnl_queue_get_copy_range(const struct nfnl_queue *queue)
return queue->queue_copy_range;
}
-static int nfnl_queue_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint64_t nfnl_queue_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct nfnl_queue *a = (struct nfnl_queue *) _a;
struct nfnl_queue *b = (struct nfnl_queue *) _b;
- int diff = 0;
+ uint64_t diff = 0;
#define NFNL_QUEUE_DIFF(ATTR, EXPR) \
ATTR_DIFF(attrs, QUEUE_ATTR_##ATTR, a, b, EXPR)
@@ -185,10 +186,10 @@ static int nfnl_queue_compare(struct nl_object *_a, struct nl_object *_b,
}
static const struct trans_tbl nfnl_queue_attrs[] = {
- __ADD(QUEUE_ATTR_GROUP, group)
- __ADD(QUEUE_ATTR_MAXLEN, maxlen)
- __ADD(QUEUE_ATTR_COPY_MODE, copy_mode)
- __ADD(QUEUE_ATTR_COPY_RANGE, copy_range)
+ __ADD(QUEUE_ATTR_GROUP, group),
+ __ADD(QUEUE_ATTR_MAXLEN, maxlen),
+ __ADD(QUEUE_ATTR_COPY_MODE, copy_mode),
+ __ADD(QUEUE_ATTR_COPY_RANGE, copy_range),
};
static char *nfnl_queue_attrs2str(int attrs, char *buf, size_t len)
diff --git a/lib/nl.c b/lib/nl.c
index 25fd59cf..bd8e3313 100644
--- a/lib/nl.c
+++ b/lib/nl.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/nl.c Core Netlink Interface
*
@@ -27,11 +28,13 @@
#include <netlink-private/netlink.h>
#include <netlink-private/socket.h>
+#include <netlink-private/utils.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/handlers.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
+#include <linux/socket.h>
/**
* @defgroup core_types Data Types
@@ -86,8 +89,13 @@
* This capability is indicated by
* `%NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE`.
*
+ * @note nl_connect() creates and sets the file descriptor. You can setup the file
+ * descriptor yourself by creating and binding it, and then calling
+ * nl_socket_set_fd(). The result will be the same.
+ *
* @see nl_socket_alloc()
* @see nl_close()
+ * @see nl_socket_set_fd()
*
* @return 0 on success or a negative error code.
*
@@ -98,95 +106,113 @@ int nl_connect(struct nl_sock *sk, int protocol)
int err, flags = 0;
int errsv;
socklen_t addrlen;
+ struct sockaddr_nl local = { 0 };
+ int try_bind = 1;
#ifdef SOCK_CLOEXEC
flags |= SOCK_CLOEXEC;
#endif
- if (sk->s_fd != -1)
- return -NLE_BAD_SOCK;
+ if (sk->s_fd != -1)
+ return -NLE_BAD_SOCK;
sk->s_fd = socket(AF_NETLINK, SOCK_RAW | flags, protocol);
if (sk->s_fd < 0) {
errsv = errno;
- NL_DBG(4, "nl_connect(%p): socket() failed with %d\n", sk, errsv);
+ NL_DBG(4, "nl_connect(%p): socket() failed with %d (%s)\n", sk, errsv,
+ nl_strerror_l(errsv));
err = -nl_syserr2nlerr(errsv);
goto errout;
}
- if (!(sk->s_flags & NL_SOCK_BUFSIZE_SET)) {
- err = nl_socket_set_buffer_size(sk, 0, 0);
- if (err < 0)
- goto errout;
- }
+ err = nl_socket_set_buffer_size(sk, 0, 0);
+ if (err < 0)
+ goto errout;
if (_nl_socket_is_local_port_unspecified (sk)) {
uint32_t port;
uint32_t used_ports[32] = { 0 };
+ int ntries = 0;
while (1) {
- port = _nl_socket_generate_local_port_no_release(sk);
-
- if (port == UINT32_MAX) {
- NL_DBG(4, "nl_connect(%p): no more unused local ports.\n", sk);
- _nl_socket_used_ports_release_all(used_ports);
- err = -NLE_EXIST;
- goto errout;
+ if (ntries++ > 5) {
+ /* try only a few times. We hit this only if many ports are already in
+ * use but allocated *outside* libnl/generate_local_port(). */
+ _nl_socket_set_local_port_no_release (sk, 0);
+ break;
}
+
+ port = _nl_socket_set_local_port_no_release(sk, 1);
+ if (port == 0)
+ break;
+
err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
sizeof(sk->s_local));
- if (err == 0)
+ if (err == 0) {
+ try_bind = 0;
break;
+ }
errsv = errno;
if (errsv == EADDRINUSE) {
NL_DBG(4, "nl_connect(%p): local port %u already in use. Retry.\n", sk, (unsigned) port);
_nl_socket_used_ports_set(used_ports, port);
} else {
- NL_DBG(4, "nl_connect(%p): bind() for port %u failed with %d\n", sk, (unsigned) port, errsv);
+ NL_DBG(4, "nl_connect(%p): bind() for port %u failed with %d (%s)\n",
+ sk, (unsigned) port, errsv, nl_strerror_l(errsv));
_nl_socket_used_ports_release_all(used_ports);
err = -nl_syserr2nlerr(errsv);
goto errout;
}
}
_nl_socket_used_ports_release_all(used_ports);
- } else {
+ }
+ if (try_bind) {
err = bind(sk->s_fd, (struct sockaddr*) &sk->s_local,
sizeof(sk->s_local));
if (err != 0) {
errsv = errno;
- NL_DBG(4, "nl_connect(%p): bind() failed with %d\n", sk, errsv);
+ NL_DBG(4, "nl_connect(%p): bind() failed with %d (%s)\n",
+ sk, errsv, nl_strerror_l(errsv));
err = -nl_syserr2nlerr(errsv);
goto errout;
}
}
- addrlen = sizeof(sk->s_local);
- err = getsockname(sk->s_fd, (struct sockaddr *) &sk->s_local,
+ addrlen = sizeof(local);
+ err = getsockname(sk->s_fd, (struct sockaddr *) &local,
&addrlen);
if (err < 0) {
+ NL_DBG(4, "nl_connect(%p): getsockname() failed with %d (%s)\n",
+ sk, errno, nl_strerror_l(errno));
err = -nl_syserr2nlerr(errno);
goto errout;
}
- if (addrlen != sizeof(sk->s_local)) {
+ if (addrlen != sizeof(local)) {
err = -NLE_NOADDR;
goto errout;
}
- if (sk->s_local.nl_family != AF_NETLINK) {
+ if (local.nl_family != AF_NETLINK) {
err = -NLE_AF_NOSUPPORT;
goto errout;
}
+ if (sk->s_local.nl_pid != local.nl_pid) {
+ /* The port id is different. That can happen if the port id was zero
+ * and kernel assigned a local port. */
+ nl_socket_set_local_port (sk, local.nl_pid);
+ }
+ sk->s_local = local;
sk->s_proto = protocol;
return 0;
errout:
- if (sk->s_fd != -1) {
- close(sk->s_fd);
- sk->s_fd = -1;
- }
+ if (sk->s_fd != -1) {
+ close(sk->s_fd);
+ sk->s_fd = -1;
+ }
return err;
}
@@ -254,8 +280,11 @@ int nl_sendto(struct nl_sock *sk, void *buf, size_t size)
ret = sendto(sk->s_fd, buf, size, 0, (struct sockaddr *)
&sk->s_peer, sizeof(sk->s_peer));
- if (ret < 0)
+ if (ret < 0) {
+ NL_DBG(4, "nl_sendto(%p): sendto() failed with %d (%s)\n",
+ sk, errno, nl_strerror_l(errno));
return -nl_syserr2nlerr(errno);
+ }
return ret;
}
@@ -312,8 +341,11 @@ int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr)
return ret;
ret = sendmsg(sk->s_fd, hdr, 0);
- if (ret < 0)
+ if (ret < 0) {
+ NL_DBG(4, "nl_sendmsg(%p): sendmsg() failed with %d (%s)\n",
+ sk, errno, nl_strerror_l(errno));
return -nl_syserr2nlerr(errno);
+ }
NL_DBG(4, "sent %d bytes\n", ret);
return ret;
@@ -349,6 +381,7 @@ int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, uns
.msg_iov = iov,
.msg_iovlen = iovlen,
};
+ char buf[CMSG_SPACE(sizeof(struct ucred))];
/* Overwrite destination if specified in the message itself, defaults
* to the peer address of the socket.
@@ -360,7 +393,6 @@ int nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, uns
/* Add credentials if present. */
creds = nlmsg_get_creds(msg);
if (creds != NULL) {
- char buf[CMSG_SPACE(sizeof(struct ucred))];
struct cmsghdr *cmsg;
hdr.msg_control = buf;
@@ -590,7 +622,9 @@ errout:
*
* This function blocks until data is available to be read unless the socket
* has been put into non-blocking mode using nl_socket_set_nonblocking() in
- * which case this function will return immediately with a return value of 0.
+ * which case this function will return immediately with a return value of
+ * -NLA_AGAIN (versions before 3.2.22 returned instead 0, in which case you
+ * should check first clear errno and then check for errno EAGAIN).
*
* The buffer size used when reading from the netlink socket and thus limiting
* the maximum size of a netlink message that can be read defaults to the size
@@ -641,13 +675,14 @@ int nl_recv(struct nl_sock *sk, struct sockaddr_nl *nla,
if (!buf || !nla)
return -NLE_INVAL;
- if (sk->s_flags & NL_MSG_PEEK)
+ if ( (sk->s_flags & NL_MSG_PEEK)
+ || (!(sk->s_flags & NL_MSG_PEEK_EXPLICIT) && sk->s_bufsize == 0))
flags |= MSG_PEEK | MSG_TRUNC;
if (page_size == 0)
page_size = getpagesize() * 4;
- iov.iov_len = sk->s_bufsize ? : page_size;
+ iov.iov_len = sk->s_bufsize ? sk->s_bufsize : page_size;
iov.iov_base = malloc(iov.iov_len);
if (!iov.iov_base) {
@@ -675,12 +710,22 @@ retry:
NL_DBG(3, "recvmsg() returned EINTR, retrying\n");
goto retry;
}
+
+ NL_DBG(4, "recvmsg(%p): nl_recv() failed with %d (%s)\n",
+ sk, errno, nl_strerror_l(errno));
retval = -nl_syserr2nlerr(errno);
goto abort;
}
if (msg.msg_flags & MSG_CTRUNC) {
void *tmp;
+
+ if (msg.msg_controllen == 0) {
+ retval = -NLE_MSG_TRUNC;
+ NL_DBG(4, "recvmsg(%p): Received unexpected control data", sk);
+ goto abort;
+ }
+
msg.msg_controllen *= 2;
tmp = realloc(msg.msg_control, msg.msg_controllen);
if (!tmp) {
@@ -693,6 +738,13 @@ retry:
if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) {
void *tmp;
+
+ /* respond with error to an incomplete message */
+ if (flags == 0) {
+ retval = -NLE_MSG_TRUNC;
+ goto abort;
+ }
+
/* Provided buffer is not long enough, enlarge it
* to size of n (which should be total length of the message)
* and try again. */
@@ -707,7 +759,7 @@ retry:
goto retry;
}
- if (flags != 0) {
+ if (flags != 0) {
/* Buffer is big enough, do the actual reading */
flags = 0;
goto retry;
@@ -867,7 +919,7 @@ continue_reading:
interrupted = 1;
}
}
-
+
/* Other side wishes to see an ack for this message */
if (hdr->nlmsg_flags & NLM_F_ACK) {
if (cb->cb_set[NL_CB_SEND_ACK])
@@ -926,10 +978,13 @@ continue_reading:
goto out;
}
} else if (e->error) {
+ NL_DBG(4, "recvmsgs(%p): RTNETLINK responded with %d (%s)\n",
+ sk, -e->error, nl_strerror_l(-e->error));
+
/* Error message reported back from kernel. */
if (cb->cb_err) {
err = cb->cb_err(&nla, e,
- cb->cb_err_arg);
+ cb->cb_err_arg);
if (err < 0)
goto out;
else if (err == NL_SKIP)
@@ -955,7 +1010,7 @@ skip:
err = 0;
hdr = nlmsg_next(hdr, &n);
}
-
+
nlmsg_free(msg);
free(buf);
free(creds);
@@ -1077,6 +1132,7 @@ struct pickup_param
int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *,
struct nlmsghdr *, struct nl_parser_param *);
struct nl_object *result;
+ int *syserror;
};
static int __store_answer(struct nl_object *obj, struct nl_parser_param *p)
@@ -1103,20 +1159,45 @@ static int __pickup_answer(struct nl_msg *msg, void *arg)
return pp->parser(NULL, &msg->nm_src, msg->nm_nlh, &parse_arg);
}
+static int __pickup_answer_syserr(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg)
+{
+ *(((struct pickup_param *) arg)->syserror) = nlerr->error;
+
+ return -nl_syserr2nlerr(nlerr->error);
+}
+
/** @endcond */
/**
* Pickup netlink answer, parse is and return object
- * @arg sk Netlink socket
- * @arg parser Parser function to parse answer
- * @arg result Result pointer to return parsed object
+ * @arg sk Netlink socket
+ * @arg parser Parser function to parse answer
+ * @arg result Result pointer to return parsed object
*
* @return 0 on success or a negative error code.
*/
int nl_pickup(struct nl_sock *sk,
- int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *,
- struct nlmsghdr *, struct nl_parser_param *),
- struct nl_object **result)
+ int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+ struct nlmsghdr *, struct nl_parser_param *),
+ struct nl_object **result)
+{
+ return nl_pickup_keep_syserr(sk, parser, result, NULL);
+}
+
+/**
+ * Pickup netlink answer, parse is and return object with preserving system error
+ * @arg sk Netlink socket
+ * @arg parser Parser function to parse answer
+ * @arg result Result pointer to return parsed object
+ * @arg syserr Result pointer for the system error in case of failure
+ *
+ * @return 0 on success or a negative error code.
+ */
+int nl_pickup_keep_syserr(struct nl_sock *sk,
+ int (*parser)(struct nl_cache_ops *, struct sockaddr_nl *,
+ struct nlmsghdr *, struct nl_parser_param *),
+ struct nl_object **result,
+ int *syserror)
{
struct nl_cb *cb;
int err;
@@ -1129,6 +1210,11 @@ int nl_pickup(struct nl_sock *sk,
return -NLE_NOMEM;
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, __pickup_answer, &pp);
+ if (syserror) {
+ *syserror = 0;
+ pp.syserror = syserror;
+ nl_cb_err(cb, NL_CB_CUSTOM, __pickup_answer_syserr, &pp);
+ }
err = nl_recvmsgs(sk, cb);
if (err < 0)
diff --git a/lib/object.c b/lib/object.c
index 52bc8736..4e14554e 100644
--- a/lib/object.c
+++ b/lib/object.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/object.c Generic Cacheable Object
*
@@ -131,7 +132,7 @@ struct nl_object *nl_object_clone(struct nl_object *obj)
new->ce_mask = obj->ce_mask;
if (size)
- memcpy((void *)new + doff, (void *)obj + doff, size);
+ memcpy((char *)new + doff, (char *)obj + doff, size);
if (ops->oo_clone) {
if (ops->oo_clone(new, obj) < 0) {
@@ -295,12 +296,12 @@ void nl_object_dump(struct nl_object *obj, struct nl_dump_params *params)
void nl_object_dump_buf(struct nl_object *obj, char *buf, size_t len)
{
- struct nl_dump_params dp = {
- .dp_buf = buf,
- .dp_buflen = len,
- };
+ struct nl_dump_params dp = {
+ .dp_buf = buf,
+ .dp_buflen = len,
+ };
- return nl_object_dump(obj, &dp);
+ nl_object_dump(obj, &dp);
}
/**
@@ -343,7 +344,7 @@ int nl_object_identical(struct nl_object *a, struct nl_object *b)
if (ops->oo_compare == NULL)
return 0;
- return !(ops->oo_compare(a, b, req_attrs, 0));
+ return !(ops->oo_compare(a, b, req_attrs, ID_COMPARISON));
}
/**
@@ -358,17 +359,42 @@ int nl_object_identical(struct nl_object *a, struct nl_object *b)
*
* @return Bitmask describing differences or 0 if they are completely identical.
*/
-uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b)
+uint64_t nl_object_diff64(struct nl_object *a, struct nl_object *b)
{
struct nl_object_ops *ops = obj_ops(a);
if (ops != obj_ops(b) || ops->oo_compare == NULL)
- return UINT_MAX;
+ return UINT64_MAX;
return ops->oo_compare(a, b, ~0, 0);
}
/**
+ * Compute 32-bit bitmask representing difference in attribute values
+ * @arg a an object
+ * @arg b another object of same type
+ *
+ * The bitmask returned is specific to an object type, each bit set represents
+ * an attribute which mismatches in either of the two objects. Unavailability
+ * of an attribute in one object and presence in the other is regarded a
+ * mismatch as well.
+ *
+ * @return Bitmask describing differences or 0 if they are completely identical.
+ * 32nd bit indicates if higher bits from the 64-bit compare were
+ * different.
+ */
+uint32_t nl_object_diff(struct nl_object *a, struct nl_object *b)
+{
+ uint64_t diff;
+
+ diff = nl_object_diff64(a, b);
+
+ return (diff & ~((uint64_t) 0xFFFFFFFF))
+ ? (uint32_t) diff | (1 << 31)
+ : (uint32_t) diff;
+}
+
+/**
* Match a filter against an object
* @arg obj object to check
* @arg filter object of same type acting as filter
@@ -383,7 +409,7 @@ int nl_object_match_filter(struct nl_object *obj, struct nl_object *filter)
if (ops != obj_ops(filter) || ops->oo_compare == NULL)
return 0;
-
+
return !(ops->oo_compare(obj, filter, filter->ce_mask,
LOOSE_COMPARISON));
}
diff --git a/lib/route/act.c b/lib/route/act.c
index 85ce445c..a0aff7fb 100644
--- a/lib/route/act.c
+++ b/lib/route/act.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/act.c Action
*
@@ -21,11 +22,21 @@
#include <netlink/utils.h>
#include <netlink-private/route/tc-api.h>
#include <netlink/route/link.h>
+#include <netlink/route/action.h>
static struct nl_object_ops act_obj_ops;
static struct nl_cache_ops rtnl_act_ops;
+struct rtnl_act * rtnl_act_next(struct rtnl_act *act)
+{
+ if (act == NULL) {
+ return NULL;
+ }
+
+ return act->a_next;
+}
+
int rtnl_act_append(struct rtnl_act **head, struct rtnl_act *new)
{
struct rtnl_act *p_act;
@@ -53,14 +64,14 @@ int rtnl_act_remove(struct rtnl_act **head, struct rtnl_act *act)
{
struct rtnl_act *a, **ap;
- for (ap = head; (a = *ap) != NULL; ap = &a->a_next)
- if (a == act)
- break;
- if (a) {
- *ap = a->a_next;
- a->a_next = NULL;
- return 0;
- }
+ for (ap = head; (a = *ap) != NULL; ap = &a->a_next)
+ if (a == act)
+ break;
+ if (a) {
+ *ap = a->a_next;
+ a->a_next = NULL;
+ return 0;
+ }
return -NLE_OBJ_NOTFOUND;
}
diff --git a/lib/route/act/gact.c b/lib/route/act/gact.c
new file mode 100644
index 00000000..e37ef9f5
--- /dev/null
+++ b/lib/route/act/gact.c
@@ -0,0 +1,183 @@
+/*
+ * lib/route/act/gact.c gact action
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2016 Sushma Sitaram <sushma.sitaram@intel.com>
+ */
+
+/**
+ * @ingroup act
+ * @defgroup act_gact GACT Editing
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/act/gact.h>
+
+static struct nla_policy gact_policy[TCA_GACT_MAX + 1] = {
+ [TCA_GACT_PARMS] = { .minlen = sizeof(struct tc_gact) },
+};
+
+static int gact_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct rtnl_gact *u = data;
+ struct nlattr *tb[TCA_GACT_MAX + 1];
+ int err;
+
+ err = tca_parse(tb, TCA_GACT_MAX, tc, gact_policy);
+ if (err < 0)
+ return err;
+
+ if (!tb[TCA_GACT_PARMS])
+ return -NLE_MISSING_ATTR;
+
+ nla_memcpy(&u->g_parm, tb[TCA_GACT_PARMS], sizeof(u->g_parm));
+
+ return 0;
+}
+
+static void gact_free_data(struct rtnl_tc *tc, void *data)
+{
+}
+
+static int gact_clone(void *_dst, void *_src)
+{
+ struct rtnl_gact *dst = _dst, *src = _src;
+
+ memcpy(&dst->g_parm, &src->g_parm, sizeof(src->g_parm));
+ return 0;
+}
+
+static void gact_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_gact *u = data;
+
+ if (!u)
+ return;
+
+ switch(u->g_parm.action){
+ case TC_ACT_UNSPEC:
+ nl_dump(p, " continue");
+ break;
+ case TC_ACT_SHOT:
+ nl_dump(p, " drop");
+ break;
+ case TC_ACT_RECLASSIFY:
+ nl_dump(p, " reclassify");
+ break;
+ case TC_ACT_OK:
+ nl_dump(p, " pass");
+ break;
+ }
+
+}
+
+static void gact_dump_details(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+}
+
+static void gact_dump_stats(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_gact *u = data;
+
+ if (!u)
+ return;
+ /* TODO */
+}
+
+
+static int gact_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct rtnl_gact *u = data;
+
+ if (!u)
+ return 0;
+
+ NLA_PUT(msg, TCA_GACT_PARMS, sizeof(u->g_parm), &u->g_parm);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_NOMEM;
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+int rtnl_gact_set_action(struct rtnl_act *act, int action)
+{
+ struct rtnl_gact *u;
+
+ if (!(u = (struct rtnl_gact *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (action > TC_ACT_SHOT || action < TC_ACT_UNSPEC)
+ return -NLE_INVAL;
+
+ switch (action) {
+ case TC_ACT_UNSPEC:
+ case TC_ACT_SHOT:
+ u->g_parm.action = action;
+ break;
+ case TC_ACT_OK:
+ case TC_ACT_RECLASSIFY:
+ default:
+ return NLE_OPNOTSUPP;
+ }
+
+ return 0;
+}
+
+int rtnl_gact_get_action(struct rtnl_act *act)
+{
+ struct rtnl_gact *u;
+
+ if (!(u = (struct rtnl_gact *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+ return u->g_parm.action;
+}
+
+
+/** @} */
+
+static struct rtnl_tc_ops gact_ops = {
+ .to_kind = "gact",
+ .to_type = RTNL_TC_TYPE_ACT,
+ .to_size = sizeof(struct rtnl_gact),
+ .to_msg_parser = gact_msg_parser,
+ .to_free_data = gact_free_data,
+ .to_clone = gact_clone,
+ .to_msg_fill = gact_msg_fill,
+ .to_dump = {
+ [NL_DUMP_LINE] = gact_dump_line,
+ [NL_DUMP_DETAILS] = gact_dump_details,
+ [NL_DUMP_STATS] = gact_dump_stats,
+ },
+};
+
+static void __init gact_init(void)
+{
+ rtnl_tc_register(&gact_ops);
+}
+
+static void __exit gact_exit(void)
+{
+ rtnl_tc_unregister(&gact_ops);
+}
+
+/** @} */
diff --git a/lib/route/act/mirred.c b/lib/route/act/mirred.c
index d047e24b..b674fb8c 100644
--- a/lib/route/act/mirred.c
+++ b/lib/route/act/mirred.c
@@ -1,5 +1,5 @@
/*
- * lib/route/cls/mirred.c mirred action
+ * lib/route/act/mirred.c mirred action
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/lib/route/act/skbedit.c b/lib/route/act/skbedit.c
new file mode 100644
index 00000000..d85265ee
--- /dev/null
+++ b/lib/route/act/skbedit.c
@@ -0,0 +1,290 @@
+/*
+ * lib/route/act/skbedit.c skbedit action
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2015 Cong Wang <xiyou.wangcong@gmail.com>
+ */
+
+/**
+ * @ingroup act
+ * @defgroup act_skbedit SKB Editing
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/act/skbedit.h>
+
+static struct nla_policy skbedit_policy[TCA_SKBEDIT_MAX + 1] = {
+ [TCA_SKBEDIT_PARMS] = { .minlen = sizeof(struct tc_skbedit) },
+ [TCA_SKBEDIT_PRIORITY] = { .type = NLA_U32 },
+ [TCA_SKBEDIT_QUEUE_MAPPING] = { .type = NLA_U16 },
+ [TCA_SKBEDIT_MARK] = { .type = NLA_U32 },
+};
+
+static int skbedit_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct rtnl_skbedit *u = data;
+ struct nlattr *tb[TCA_SKBEDIT_MAX + 1];
+ int err;
+
+ err = tca_parse(tb, TCA_SKBEDIT_MAX, tc, skbedit_policy);
+ if (err < 0)
+ return err;
+
+ if (!tb[TCA_SKBEDIT_PARMS])
+ return -NLE_MISSING_ATTR;
+
+ u->s_flags = 0;
+ if (tb[TCA_SKBEDIT_PRIORITY] != NULL) {
+ u->s_flags |= SKBEDIT_F_PRIORITY;
+ u->s_prio = nla_get_u32(tb[TCA_SKBEDIT_PRIORITY]);
+ }
+
+ if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) {
+ u->s_flags |= SKBEDIT_F_QUEUE_MAPPING;
+ u->s_queue_mapping = nla_get_u16(tb[TCA_SKBEDIT_QUEUE_MAPPING]);
+ }
+
+ if (tb[TCA_SKBEDIT_MARK] != NULL) {
+ u->s_flags |= SKBEDIT_F_MARK;
+ u->s_mark = nla_get_u32(tb[TCA_SKBEDIT_MARK]);
+ }
+
+ return 0;
+}
+
+static void skbedit_free_data(struct rtnl_tc *tc, void *data)
+{
+}
+
+static int skbedit_clone(void *_dst, void *_src)
+{
+ struct rtnl_skbedit *dst = _dst, *src = _src;
+
+ memcpy(dst, src, sizeof(*src));
+ return 0;
+}
+
+static void skbedit_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_skbedit *u = data;
+
+ if (!u)
+ return;
+
+ if (u->s_flags & SKBEDIT_F_PRIORITY)
+ nl_dump(p, " priority %u", u->s_prio);
+
+ if (u->s_flags & SKBEDIT_F_MARK)
+ nl_dump(p, " mark %u", u->s_mark);
+
+ if (u->s_flags & SKBEDIT_F_QUEUE_MAPPING)
+ nl_dump(p, " queue_mapping %u", u->s_queue_mapping);
+
+ switch(u->s_parm.action){
+ case TC_ACT_UNSPEC:
+ nl_dump(p, " unspecified");
+ break;
+ case TC_ACT_PIPE:
+ nl_dump(p, " pipe");
+ break;
+ case TC_ACT_STOLEN:
+ nl_dump(p, " stolen");
+ break;
+ case TC_ACT_SHOT:
+ nl_dump(p, " shot");
+ break;
+ case TC_ACT_QUEUED:
+ nl_dump(p, " queued");
+ break;
+ case TC_ACT_REPEAT:
+ nl_dump(p, " repeat");
+ break;
+ }
+}
+
+static void skbedit_dump_details(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+}
+
+static void skbedit_dump_stats(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_skbedit *u = data;
+
+ if (!u)
+ return;
+ /* TODO */
+}
+
+
+static int skbedit_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct rtnl_skbedit *u = data;
+
+ if (!u)
+ return 0;
+
+ NLA_PUT(msg, TCA_SKBEDIT_PARMS, sizeof(u->s_parm), &u->s_parm);
+
+ if (u->s_flags & SKBEDIT_F_MARK)
+ NLA_PUT_U32(msg, TCA_SKBEDIT_MARK, u->s_mark);
+
+ if (u->s_flags & SKBEDIT_F_PRIORITY)
+ NLA_PUT_U32(msg, TCA_SKBEDIT_PRIORITY, u->s_prio);
+
+ if (u->s_flags & SKBEDIT_F_QUEUE_MAPPING)
+ NLA_PUT_U32(msg, TCA_SKBEDIT_QUEUE_MAPPING, u->s_queue_mapping);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_NOMEM;
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+int rtnl_skbedit_set_action(struct rtnl_act *act, int action)
+{
+ struct rtnl_skbedit *u;
+
+ if (!(u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (action > TC_ACT_REPEAT || action < TC_ACT_UNSPEC)
+ return -NLE_INVAL;
+
+ u->s_parm.action = action;
+ return 0;
+}
+
+int rtnl_skbedit_get_action(struct rtnl_act *act)
+{
+ struct rtnl_skbedit *u;
+
+ if (!(u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+ return u->s_parm.action;
+}
+
+int rtnl_skbedit_set_queue_mapping(struct rtnl_act *act, uint16_t index)
+{
+ struct rtnl_skbedit *u;
+
+ if (!(u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ u->s_queue_mapping = index;
+ u->s_flags |= SKBEDIT_F_QUEUE_MAPPING;
+ return 0;
+}
+
+int rtnl_skbedit_get_queue_mapping(struct rtnl_act *act, uint16_t *index)
+{
+ struct rtnl_skbedit *u;
+
+ u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act));
+ if (!u)
+ return -NLE_NOMEM;
+ if (!(u->s_flags & SKBEDIT_F_QUEUE_MAPPING))
+ return -NLE_NOATTR;
+
+ *index = u->s_queue_mapping;
+ return 0;
+}
+
+int rtnl_skbedit_set_mark(struct rtnl_act *act, uint32_t mark)
+{
+ struct rtnl_skbedit *u;
+
+ if (!(u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ u->s_mark = mark;
+ u->s_flags |= SKBEDIT_F_MARK;
+ return 0;
+}
+
+int rtnl_skbedit_get_mark(struct rtnl_act *act, uint32_t *mark)
+{
+ struct rtnl_skbedit *u;
+
+ u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act));
+ if (!u)
+ return -NLE_NOMEM;
+ if (!(u->s_flags & SKBEDIT_F_MARK))
+ return -NLE_NOATTR;
+
+ *mark = u->s_mark;
+ return 0;
+}
+
+int rtnl_skbedit_set_priority(struct rtnl_act *act, uint32_t prio)
+{
+ struct rtnl_skbedit *u;
+
+ if (!(u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ u->s_prio = prio;
+ u->s_flags |= SKBEDIT_F_PRIORITY;
+ return 0;
+}
+
+int rtnl_skbedit_get_priority(struct rtnl_act *act, uint32_t *prio)
+{
+ struct rtnl_skbedit *u;
+
+ u = (struct rtnl_skbedit *) rtnl_tc_data(TC_CAST(act));
+ if (!u)
+ return -NLE_NOMEM;
+ if (!(u->s_flags & SKBEDIT_F_PRIORITY))
+ return -NLE_NOATTR;
+
+ *prio = u->s_prio;
+ return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops skbedit_ops = {
+ .to_kind = "skbedit",
+ .to_type = RTNL_TC_TYPE_ACT,
+ .to_size = sizeof(struct rtnl_skbedit),
+ .to_msg_parser = skbedit_msg_parser,
+ .to_free_data = skbedit_free_data,
+ .to_clone = skbedit_clone,
+ .to_msg_fill = skbedit_msg_fill,
+ .to_dump = {
+ [NL_DUMP_LINE] = skbedit_dump_line,
+ [NL_DUMP_DETAILS] = skbedit_dump_details,
+ [NL_DUMP_STATS] = skbedit_dump_stats,
+ },
+};
+
+static void __init skbedit_init(void)
+{
+ rtnl_tc_register(&skbedit_ops);
+}
+
+static void __exit skbedit_exit(void)
+{
+ rtnl_tc_unregister(&skbedit_ops);
+}
+
+/** @} */
diff --git a/lib/route/act/vlan.c b/lib/route/act/vlan.c
new file mode 100644
index 00000000..69b6f240
--- /dev/null
+++ b/lib/route/act/vlan.c
@@ -0,0 +1,426 @@
+/*
+ * lib/route/act/vlan.c vlan action
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
+ */
+
+/**
+ * @ingroup act
+ * @defgroup act_vlan VLAN Manipulation
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/act/vlan.h>
+
+
+#define VLAN_F_VID (1 << 0)
+#define VLAN_F_PROTO (1 << 1)
+#define VLAN_F_PRIO (1 << 2)
+#define VLAN_F_ACT (1 << 3)
+#define VLAN_F_MODE (1 << 4)
+
+static struct nla_policy vlan_policy[TCA_VLAN_MAX + 1] = {
+ [TCA_VLAN_PARMS] = { .minlen = sizeof(struct tc_vlan) },
+ [TCA_VLAN_PUSH_VLAN_ID] = { .type = NLA_U16 },
+ [TCA_VLAN_PUSH_VLAN_PROTOCOL] = { .type = NLA_U16 },
+ [TCA_VLAN_PUSH_VLAN_PRIORITY] = { .type = NLA_U8 },
+};
+
+static int vlan_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct rtnl_vlan *v = data;
+ struct nlattr *tb[TCA_VLAN_MAX + 1];
+ int err;
+
+ err = tca_parse(tb, TCA_VLAN_MAX, tc, vlan_policy);
+ if (err < 0)
+ return err;
+
+ v->v_flags = 0;
+ if (!tb[TCA_VLAN_PARMS])
+ return -NLE_MISSING_ATTR;
+ else {
+ nla_memcpy(&v->v_parm, tb[TCA_VLAN_PARMS], sizeof(v->v_parm));
+ v->v_flags |= VLAN_F_ACT;
+ v->v_flags |= VLAN_F_MODE;
+ }
+
+ if (tb[TCA_VLAN_PUSH_VLAN_ID]) {
+ v->v_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
+ v->v_flags |= VLAN_F_VID;
+ }
+
+ if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) {
+ v->v_proto = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]);
+ v->v_flags |= VLAN_F_PROTO;
+ }
+
+ if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) {
+ v->v_prio = nla_get_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]);
+ v->v_flags |= VLAN_F_PRIO;
+ }
+
+ return 0;
+}
+
+static int vlan_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct rtnl_vlan *v = data;
+
+ if (!v)
+ return 0;
+ if (!(v->v_flags & VLAN_F_MODE))
+ return -NLE_MISSING_ATTR;
+
+ NLA_PUT(msg, TCA_VLAN_PARMS, sizeof(v->v_parm), &v->v_parm);
+
+ /* vid is required for PUSH & MODIFY modes */
+ if ((v->v_parm.v_action != TCA_VLAN_ACT_POP) && !(v->v_flags & VLAN_F_VID))
+ return -NLE_MISSING_ATTR;
+
+ if (v->v_flags & VLAN_F_VID)
+ NLA_PUT_U16(msg, TCA_VLAN_PUSH_VLAN_ID, v->v_vid);
+
+ if (v->v_flags & VLAN_F_PROTO)
+ NLA_PUT_U16(msg, TCA_VLAN_PUSH_VLAN_PROTOCOL, v->v_proto);
+
+ if (v->v_flags & VLAN_F_PRIO)
+ NLA_PUT_U8(msg, TCA_VLAN_PUSH_VLAN_PRIORITY, v->v_prio);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_NOMEM;
+}
+
+static void vlan_free_data(struct rtnl_tc *tc, void *data)
+{
+}
+
+static int vlan_clone(void *_dst, void *_src)
+{
+ struct rtnl_vlan *dst = _dst, *src = _src;
+
+ memcpy(&dst->v_parm, &src->v_parm, sizeof(src->v_parm));
+ return 0;
+}
+
+static void vlan_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_vlan *v = data;
+
+ if (!v)
+ return;
+
+ if (!(v->v_flags & VLAN_F_ACT))
+ return;
+
+ if (TC_ACT_EXT_CMP(v->v_parm.action, TC_ACT_GOTO_CHAIN))
+ nl_dump(p, " goto chain %u", v->v_parm.action & TC_ACT_EXT_VAL_MASK);
+
+ if (TC_ACT_EXT_CMP(v->v_parm.action, TC_ACT_JUMP))
+ nl_dump(p, " jump %u", v->v_parm.action & TC_ACT_EXT_VAL_MASK);
+
+ switch(v->v_parm.action){
+ case TC_ACT_UNSPEC:
+ nl_dump(p, " unspecified");
+ break;
+ case TC_ACT_PIPE:
+ nl_dump(p, " pipe");
+ break;
+ case TC_ACT_STOLEN:
+ nl_dump(p, " stolen");
+ break;
+ case TC_ACT_SHOT:
+ nl_dump(p, " shot");
+ break;
+ case TC_ACT_QUEUED:
+ nl_dump(p, " queued");
+ break;
+ case TC_ACT_REPEAT:
+ nl_dump(p, " repeat");
+ break;
+ }
+}
+
+static void vlan_dump_details(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_vlan *v = data;
+
+ if (!v)
+ return;
+
+ if (v->v_flags & VLAN_F_MODE) {
+ switch (v->v_parm.v_action) {
+ case TCA_VLAN_ACT_POP:
+ nl_dump(p, " mode POP");
+ break;
+ case TCA_VLAN_ACT_PUSH:
+ nl_dump(p, " mode PUSH");
+ break;
+ case TCA_VLAN_ACT_MODIFY:
+ nl_dump(p, " mode MODIFY");
+ break;
+ }
+ }
+
+ if (v->v_flags & VLAN_F_VID)
+ nl_dump(p, " vlan id %u", v->v_vid);
+
+ if (v->v_flags & VLAN_F_PRIO)
+ nl_dump(p, " priority %u", v->v_prio);
+
+ if (v->v_flags & VLAN_F_PROTO)
+ nl_dump(p, " protocol %u", v->v_proto);
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+/**
+ * Set vlan mode
+ * @arg act vlan action
+ * @arg mode one of (TCA_VLAN_ACT_*: POP, PUSH, MODIFY)
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_vlan_set_mode(struct rtnl_act *act, int mode)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (mode > TCA_VLAN_ACT_MODIFY)
+ return -NLE_RANGE;
+
+ v->v_parm.v_action = mode;
+ v->v_flags |= VLAN_F_MODE;
+
+ return 0;
+}
+
+/**
+ * Get vlan mode
+ * @arg act vlan action
+ * @arg out_mode vlan mode output paramter
+ * @return 0 on success if the vlan mode was returned or a negative error code.
+*/
+int rtnl_vlan_get_mode(struct rtnl_act *act, int *out_mode)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_INVAL;
+
+ if (!(v->v_flags & VLAN_F_MODE))
+ return -NLE_MISSING_ATTR;
+
+ *out_mode = v->v_parm.v_action;
+ return 0;
+}
+
+/**
+ * Set general action
+ * @arg act vlan action
+ * @arg action one of (TCA_ACT_*: PIPE, SHOT, GOTO_CHAIN, etc)
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_vlan_set_action(struct rtnl_act *act, int action)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ v->v_parm.action = action;
+ v->v_flags |= VLAN_F_ACT;
+
+ return 0;
+}
+
+/**
+ * Get general action
+ * @arg act vlan action
+ * @arg out_action output parameter
+ * @return general 0 if out_action was set or a negative error code.
+*/
+int rtnl_vlan_get_action(struct rtnl_act *act, int *out_action)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_INVAL;
+
+ if (!(v->v_flags & VLAN_F_ACT))
+ return -NLE_MISSING_ATTR;
+
+ *out_action = v->v_parm.action;
+ return 0;
+}
+
+/**
+ * Set protocol
+ * @arg act vlan action
+ * @arg protocol one of (ETH_P_8021Q || ETH_P_8021AD)
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_vlan_set_protocol(struct rtnl_act *act, uint16_t protocol)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ v->v_proto = protocol;
+ v->v_flags |= VLAN_F_PROTO;
+
+ return 0;
+}
+
+/**
+ * Get protocol
+ * @arg act vlan action
+ * @arg out_protocol protocol output argument
+ * @return 0 if the protocol was returned or a negative error code.
+*/
+int rtnl_vlan_get_protocol(struct rtnl_act *act, uint16_t *out_protocol)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_INVAL;
+
+ if (!(v->v_flags & VLAN_F_PROTO))
+ return -NLE_MISSING_ATTR;
+
+ *out_protocol = v->v_proto;
+ return 0;
+}
+
+/**
+ * Set vlan id
+ * @arg act vlan action
+ * @arg vid vlan id
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_vlan_set_vlan_id(struct rtnl_act *act, uint16_t vid)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (vid > 4095)
+ return -NLE_RANGE;
+
+ v->v_vid = vid;
+ v->v_flags |= VLAN_F_VID;
+
+ return 0;
+}
+
+/**
+ * Get vlan id
+ * @arg act vlan action
+ * @arg out_vid output vlan id
+ * @return 0 if the vlan id was returned or a negative error code.
+*/
+int rtnl_vlan_get_vlan_id(struct rtnl_act *act, uint16_t *out_vid)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_INVAL;
+
+ if (!(v->v_flags & VLAN_F_VID))
+ return -NLE_MISSING_ATTR;
+
+ *out_vid = v->v_vid;
+ return 0;
+}
+
+/**
+ * Set vlan prio
+ * @arg act vlan action
+ * @arg prio vlan priority (0 - 7)
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_vlan_set_vlan_prio(struct rtnl_act *act, uint8_t prio)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (prio > 7)
+ return -NLE_RANGE;
+
+ v->v_prio = prio;
+ v->v_flags |= VLAN_F_PRIO;
+
+ return 0;
+}
+
+/**
+ * Get vlan prio
+ * @arg act vlan action
+ * @arg out_prio the output vlan prio
+ * @return 0 if the vlan prio was returned or a negative error code.
+*/
+int rtnl_vlan_get_vlan_prio(struct rtnl_act *act, uint8_t *out_prio)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_INVAL;
+
+ if (!(v->v_flags & VLAN_F_PRIO))
+ return -NLE_MISSING_ATTR;
+
+ *out_prio = v->v_prio;
+ return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops vlan_ops = {
+ .to_kind = "vlan",
+ .to_type = RTNL_TC_TYPE_ACT,
+ .to_size = sizeof(struct rtnl_vlan),
+ .to_msg_parser = vlan_msg_parser,
+ .to_free_data = vlan_free_data,
+ .to_clone = vlan_clone,
+ .to_msg_fill = vlan_msg_fill,
+ .to_dump = {
+ [NL_DUMP_LINE] = vlan_dump_line,
+ [NL_DUMP_DETAILS] = vlan_dump_details,
+ },
+};
+
+static void __init vlan_init(void)
+{
+ rtnl_tc_register(&vlan_ops);
+}
+
+static void __exit vlan_exit(void)
+{
+ rtnl_tc_unregister(&vlan_ops);
+}
+
+/** @} */
diff --git a/lib/route/addr.c b/lib/route/addr.c
index e6e91d28..f65e7e9b 100644
--- a/lib/route/addr.c
+++ b/lib/route/addr.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/addr.c Addresses
*
@@ -241,34 +242,69 @@ static int addr_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
addr->ce_mask |= ADDR_ATTR_CACHEINFO;
}
- if (tb[IFA_LOCAL]) {
- addr->a_local = nl_addr_alloc_attr(tb[IFA_LOCAL], family);
+ if (family == AF_INET) {
+ uint32_t null = 0;
+
+ /* for IPv4/AF_INET, kernel always sets IFA_LOCAL and IFA_ADDRESS, unless it
+ * is effectively 0.0.0.0. */
+ if (tb[IFA_LOCAL])
+ addr->a_local = nl_addr_alloc_attr(tb[IFA_LOCAL], family);
+ else
+ addr->a_local = nl_addr_build(family, &null, sizeof (null));
if (!addr->a_local)
goto errout_nomem;
addr->ce_mask |= ADDR_ATTR_LOCAL;
- plen_addr = addr->a_local;
- }
-
- if (tb[IFA_ADDRESS]) {
- struct nl_addr *a;
- a = nl_addr_alloc_attr(tb[IFA_ADDRESS], family);
- if (!a)
+ if (tb[IFA_ADDRESS])
+ addr->a_peer = nl_addr_alloc_attr(tb[IFA_ADDRESS], family);
+ else
+ addr->a_peer = nl_addr_build(family, &null, sizeof (null));
+ if (!addr->a_peer)
goto errout_nomem;
- /* IPv6 sends the local address as IFA_ADDRESS with
- * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
- * with IFA_ADDRESS being the peer address if they differ */
- if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) {
- nl_addr_put(addr->a_local);
- addr->a_local = a;
- addr->ce_mask |= ADDR_ATTR_LOCAL;
- } else {
- addr->a_peer = a;
+ if (!nl_addr_cmp (addr->a_local, addr->a_peer)) {
+ /* having IFA_ADDRESS equal to IFA_LOCAL does not really mean
+ * there is no peer. It means the peer is equal to the local address,
+ * which is the case for "normal" addresses.
+ *
+ * Still, clear the peer and pretend it is unset for backward
+ * compatibility. */
+ nl_addr_put(addr->a_peer);
+ addr->a_peer = NULL;
+ } else
addr->ce_mask |= ADDR_ATTR_PEER;
+
+ plen_addr = addr->a_local;
+ } else {
+ if (tb[IFA_LOCAL]) {
+ addr->a_local = nl_addr_alloc_attr(tb[IFA_LOCAL], family);
+ if (!addr->a_local)
+ goto errout_nomem;
+ addr->ce_mask |= ADDR_ATTR_LOCAL;
+ plen_addr = addr->a_local;
}
- plen_addr = a;
+ if (tb[IFA_ADDRESS]) {
+ struct nl_addr *a;
+
+ a = nl_addr_alloc_attr(tb[IFA_ADDRESS], family);
+ if (!a)
+ goto errout_nomem;
+
+ /* IPv6 sends the local address as IFA_ADDRESS with
+ * no IFA_LOCAL, IPv4 sends both IFA_LOCAL and IFA_ADDRESS
+ * with IFA_ADDRESS being the peer address if they differ */
+ if (!tb[IFA_LOCAL] || !nl_addr_cmp(a, addr->a_local)) {
+ nl_addr_put(addr->a_local);
+ addr->a_local = a;
+ addr->ce_mask |= ADDR_ATTR_LOCAL;
+ } else {
+ addr->a_peer = a;
+ addr->ce_mask |= ADDR_ATTR_PEER;
+ }
+
+ plen_addr = a;
+ }
}
if (plen_addr)
@@ -429,12 +465,33 @@ static void addr_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
addr_dump_details(obj, p);
}
-static int addr_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint32_t addr_id_attrs_get(struct nl_object *obj)
+{
+ struct rtnl_addr *addr = (struct rtnl_addr *)obj;
+ uint32_t rv;
+
+ switch (addr->a_family) {
+ case AF_INET:
+ rv = (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX |
+ ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN);
+ if (addr->a_peer)
+ rv |= ADDR_ATTR_PEER;
+ return rv;
+ case AF_INET6:
+ return (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX |
+ ADDR_ATTR_LOCAL);
+ default:
+ return (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX |
+ ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN);
+ }
+}
+
+static uint64_t addr_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct rtnl_addr *a = (struct rtnl_addr *) _a;
struct rtnl_addr *b = (struct rtnl_addr *) _b;
- int diff = 0;
+ uint64_t diff = 0;
#define ADDR_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ADDR_ATTR_##ATTR, a, b, EXPR)
@@ -442,12 +499,27 @@ static int addr_compare(struct nl_object *_a, struct nl_object *_b,
diff |= ADDR_DIFF(FAMILY, a->a_family != b->a_family);
diff |= ADDR_DIFF(SCOPE, a->a_scope != b->a_scope);
diff |= ADDR_DIFF(LABEL, strcmp(a->a_label, b->a_label));
- diff |= ADDR_DIFF(PEER, nl_addr_cmp(a->a_peer, b->a_peer));
+ if (attrs & ADDR_ATTR_PEER) {
+ if ( (flags & ID_COMPARISON)
+ && a->a_family == AF_INET
+ && b->a_family == AF_INET
+ && a->a_peer
+ && b->a_peer
+ && a->a_prefixlen == b->a_prefixlen) {
+ /* when comparing two IPv4 addresses for id-equality, the network part
+ * of the PEER address shall be compared.
+ */
+ diff |= ADDR_DIFF(PEER, nl_addr_cmp_prefix(a->a_peer, b->a_peer));
+ } else
+ diff |= ADDR_DIFF(PEER, nl_addr_cmp(a->a_peer, b->a_peer));
+ }
diff |= ADDR_DIFF(LOCAL, nl_addr_cmp(a->a_local, b->a_local));
diff |= ADDR_DIFF(MULTICAST, nl_addr_cmp(a->a_multicast,
b->a_multicast));
diff |= ADDR_DIFF(BROADCAST, nl_addr_cmp(a->a_bcast, b->a_bcast));
diff |= ADDR_DIFF(ANYCAST, nl_addr_cmp(a->a_anycast, b->a_anycast));
+ diff |= ADDR_DIFF(CACHEINFO, memcmp(&a->a_cacheinfo, &b->a_cacheinfo,
+ sizeof (a->a_cacheinfo)));
if (flags & LOOSE_COMPARISON)
diff |= ADDR_DIFF(FLAGS,
@@ -461,17 +533,17 @@ static int addr_compare(struct nl_object *_a, struct nl_object *_b,
}
static const struct trans_tbl addr_attrs[] = {
- __ADD(ADDR_ATTR_FAMILY, family)
- __ADD(ADDR_ATTR_PREFIXLEN, prefixlen)
- __ADD(ADDR_ATTR_FLAGS, flags)
- __ADD(ADDR_ATTR_SCOPE, scope)
- __ADD(ADDR_ATTR_IFINDEX, ifindex)
- __ADD(ADDR_ATTR_LABEL, label)
- __ADD(ADDR_ATTR_CACHEINFO, cacheinfo)
- __ADD(ADDR_ATTR_PEER, peer)
- __ADD(ADDR_ATTR_LOCAL, local)
- __ADD(ADDR_ATTR_BROADCAST, broadcast)
- __ADD(ADDR_ATTR_MULTICAST, multicast)
+ __ADD(ADDR_ATTR_FAMILY, family),
+ __ADD(ADDR_ATTR_PREFIXLEN, prefixlen),
+ __ADD(ADDR_ATTR_FLAGS, flags),
+ __ADD(ADDR_ATTR_SCOPE, scope),
+ __ADD(ADDR_ATTR_IFINDEX, ifindex),
+ __ADD(ADDR_ATTR_LABEL, label),
+ __ADD(ADDR_ATTR_CACHEINFO, cacheinfo),
+ __ADD(ADDR_ATTR_PEER, peer),
+ __ADD(ADDR_ATTR_LOCAL, local),
+ __ADD(ADDR_ATTR_BROADCAST, broadcast),
+ __ADD(ADDR_ATTR_MULTICAST, multicast),
};
static char *addr_attrs2str(int attrs, char *buf, size_t len)
@@ -1061,15 +1133,15 @@ uint32_t rtnl_addr_get_last_update_time(struct rtnl_addr *addr)
*/
static const struct trans_tbl addr_flags[] = {
- __ADD(IFA_F_SECONDARY, secondary)
- __ADD(IFA_F_NODAD, nodad)
- __ADD(IFA_F_OPTIMISTIC, optimistic)
- __ADD(IFA_F_HOMEADDRESS, homeaddress)
- __ADD(IFA_F_DEPRECATED, deprecated)
- __ADD(IFA_F_TENTATIVE, tentative)
- __ADD(IFA_F_PERMANENT, permanent)
- __ADD(IFA_F_MANAGETEMPADDR, mngtmpaddr)
- __ADD(IFA_F_NOPREFIXROUTE, noprefixroute)
+ __ADD(IFA_F_SECONDARY, secondary),
+ __ADD(IFA_F_NODAD, nodad),
+ __ADD(IFA_F_OPTIMISTIC, optimistic),
+ __ADD(IFA_F_HOMEADDRESS, homeaddress),
+ __ADD(IFA_F_DEPRECATED, deprecated),
+ __ADD(IFA_F_TENTATIVE, tentative),
+ __ADD(IFA_F_PERMANENT, permanent),
+ __ADD(IFA_F_MANAGETEMPADDR, mngtmpaddr),
+ __ADD(IFA_F_NOPREFIXROUTE, noprefixroute),
};
char *rtnl_addr_flags2str(int flags, char *buf, size_t size)
@@ -1098,6 +1170,7 @@ static struct nl_object_ops addr_obj_ops = {
},
.oo_compare = addr_compare,
.oo_attrs2str = addr_attrs2str,
+ .oo_id_attrs_get = addr_id_attrs_get,
.oo_id_attrs = (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX |
ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN),
};
diff --git a/lib/route/class.c b/lib/route/class.c
index 56ad1d86..d1641126 100644
--- a/lib/route/class.c
+++ b/lib/route/class.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/class.c Traffic Classes
*
@@ -367,6 +368,38 @@ struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex,
return NULL;
}
+/**
+ * Search class by interface index and parent
+ * @arg cache Traffic class cache
+ * @arg ifindex Interface index
+ * @arg parent Handle of parent qdisc
+ *
+ * Searches a class cache previously allocated with rtnl_class_alloc_cache()
+ * and searches for a class matching the interface index and parent qdisc.
+ *
+ * The reference counter is incremented before returning the class, therefore
+ * the reference must be given back with rtnl_class_put() after usage.
+ *
+ * @return pointer to class inside the cache or NULL if no match was found.
+ */
+struct rtnl_class *rtnl_class_get_by_parent(struct nl_cache *cache, int ifindex,
+ uint32_t parent)
+{
+ struct rtnl_class *class;
+
+ if (cache->c_ops != &rtnl_class_ops)
+ return NULL;
+
+ nl_list_for_each_entry(class, &cache->c_items, ce_list) {
+ if (class->c_parent == parent && class->c_ifindex == ifindex) {
+ nl_object_get((struct nl_object *) class);
+ return class;
+ }
+ }
+
+ return NULL;
+}
+
/** @} */
/**
diff --git a/lib/route/classid.c b/lib/route/classid.c
index f2d3a01c..9dcf993d 100644
--- a/lib/route/classid.c
+++ b/lib/route/classid.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/classid.c ClassID Management
*
@@ -328,7 +329,7 @@ int rtnl_tc_read_classid_file(void)
}
}
- if (!(fd = fopen(path, "r"))) {
+ if (!(fd = fopen(path, "re"))) {
err = -nl_syserr2nlerr(errno);
goto errout;
}
@@ -402,7 +403,7 @@ int rtnl_classid_generate(const char *name, uint32_t *result, uint32_t parent)
if (build_sysconf_path(&path, "classid") < 0)
return -NLE_NOMEM;
- if (!(fd = fopen(path, "a"))) {
+ if (!(fd = fopen(path, "ae"))) {
err = -nl_syserr2nlerr(errno);
goto errout;
}
@@ -444,10 +445,11 @@ static void __init classid_init(void)
NL_DBG(1, "Failed to read classid file: %s\n", nl_geterror(err));
}
-static void free_map(void *map) {
+static void free_map(void *map)
+{
free(((struct classid_map *)map)->name);
free(map);
-};
+}
static void __exit classid_exit(void)
{
diff --git a/lib/route/cls.c b/lib/route/cls.c
index 649a7d04..fa87cd40 100644
--- a/lib/route/cls.c
+++ b/lib/route/cls.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/classifier.c Classifier
*
@@ -324,7 +325,8 @@ int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
*
* @return 0 on success or a negative error code.
*/
-int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result)
+int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent,
+ struct nl_cache **result)
{
struct nl_cache * cache;
int err;
@@ -344,6 +346,24 @@ int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, st
return 0;
}
+/**
+ * Set interface index and parent handle for classifier cache.
+ * @arg cache Pointer to cache
+ * @arg parent Parent qdisc/traffic class class
+ *
+ * Set the interface index and parent handle of a classifier cache.
+ * This is useful for reusing some existed classifier cache to reduce
+ * the overhead introduced by memory allocation.
+ *
+ * @return void.
+ */
+void rtnl_cls_cache_set_tc_params(struct nl_cache *cache,
+ int ifindex, uint32_t parent)
+{
+ cache->c_iarg1 = ifindex;
+ cache->c_iarg2 = parent;
+}
+
/** @} */
static void cls_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p)
diff --git a/lib/route/cls/basic.c b/lib/route/cls/basic.c
index 6af3844b..3581c60f 100644
--- a/lib/route/cls/basic.c
+++ b/lib/route/cls/basic.c
@@ -220,6 +220,7 @@ struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls)
int rtnl_basic_add_action(struct rtnl_cls *cls, struct rtnl_act *act)
{
struct rtnl_basic *b;
+ int err;
if (!act)
return 0;
@@ -228,9 +229,25 @@ int rtnl_basic_add_action(struct rtnl_cls *cls, struct rtnl_act *act)
return -NLE_NOMEM;
b->b_mask |= BASIC_ATTR_ACTION;
+ if ((err = rtnl_act_append(&b->b_act, act)))
+ return err;
+
/* In case user frees it */
rtnl_act_get(act);
- return rtnl_act_append(&b->b_act, act);
+ return 0;
+}
+
+struct rtnl_act* rtnl_basic_get_action(struct rtnl_cls *cls)
+{
+ struct rtnl_basic *b;
+
+ if (!(b = rtnl_tc_data_peek(TC_CAST(cls))))
+ return NULL;
+
+ if (!(b->b_mask & BASIC_ATTR_ACTION))
+ return NULL;
+
+ return b->b_act;
}
int rtnl_basic_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
diff --git a/lib/route/cls/cgroup.c b/lib/route/cls/cgroup.c
index c5b75612..b1452618 100644
--- a/lib/route/cls/cgroup.c
+++ b/lib/route/cls/cgroup.c
@@ -34,9 +34,22 @@ static struct nla_policy cgroup_policy[TCA_CGROUP_MAX+1] = {
[TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED },
};
-static int cgroup_clone(void *dst, void *src)
+static int cgroup_clone(void *_dst, void *_src)
{
- return -NLE_OPNOTSUPP;
+ struct rtnl_cgroup *dst = NULL, *src = _src;
+
+ dst = calloc(1, sizeof(*dst));
+ if (!dst)
+ return -NLE_NOMEM;
+
+ dst->cg_mask = src->cg_mask;
+ dst->cg_ematch = rtnl_ematch_tree_clone(src->cg_ematch);
+ if (!dst) {
+ free(dst);
+ return -NLE_NOMEM;
+ }
+
+ return 0;
}
static void cgroup_free_data(struct rtnl_tc *tc, void *data)
diff --git a/lib/route/cls/ematch.c b/lib/route/cls/ematch.c
index 6cbe2744..18f5be9f 100644
--- a/lib/route/cls/ematch.c
+++ b/lib/route/cls/ematch.c
@@ -22,6 +22,7 @@
#include <netlink/route/classifier.h>
#include <netlink/route/cls/ematch.h>
#include <netlink/route/cls/ematch/cmp.h>
+#include <linux/tc_ematch/tc_em_cmp.h>
#include "ematch_syntax.h"
#include "ematch_grammar.h"
@@ -288,6 +289,63 @@ void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree)
free(tree);
}
+static int clone_ematch_list(struct nl_list_head *dst, struct nl_list_head *src)
+{
+ struct rtnl_ematch *new = NULL, *pos = NULL;
+
+ nl_list_for_each_entry(pos, src, e_list) {
+ new = rtnl_ematch_alloc();
+ if (!new)
+ goto nomem;
+
+ new->e_id = pos->e_id;
+ new->e_kind = pos->e_kind;
+ new->e_flags = pos->e_flags;
+ new->e_index = pos->e_index;
+ new->e_datalen = pos->e_datalen;
+
+ if (pos->e_ops) {
+ if (rtnl_ematch_set_ops(new, pos->e_ops))
+ goto nomem;
+ }
+
+ if (!nl_list_empty(&pos->e_childs)) {
+ if (clone_ematch_list(&new->e_childs, &pos->e_childs) < 0)
+ goto nomem;
+ }
+ nl_list_add_tail(&new->e_list, dst);
+ }
+
+ return 0;
+
+nomem:
+ if (new)
+ free(new);
+ free_ematch_list(dst);
+ return -NLE_NOMEM;
+}
+
+/**
+ * Clone ematch tree object
+ * @arg src ematch tree object
+ *
+ * This function clones the ematch tree and all ematches attached to it.
+ */
+struct rtnl_ematch_tree *rtnl_ematch_tree_clone(struct rtnl_ematch_tree *src)
+{
+ struct rtnl_ematch_tree *dst = NULL;
+
+ if (!src)
+ return NULL;
+
+ if (!(dst = rtnl_ematch_tree_alloc(src->et_progid)))
+ return NULL;
+
+ clone_ematch_list(&dst->et_list, &src->et_list);
+
+ return dst;
+}
+
/**
* Add ematch object to the end of the ematch tree
* @arg tree ematch tree object
@@ -407,7 +465,7 @@ int rtnl_ematch_parse_attr(struct nlattr *attr, struct rtnl_ematch_tree **result
}
hdr = nla_data(a);
- data = nla_data(a) + NLA_ALIGN(sizeof(*hdr));
+ data = (char *) nla_data(a) + NLA_ALIGN(sizeof(*hdr));
len = nla_len(a) - NLA_ALIGN(sizeof(*hdr));
NL_DBG(3, "ematch attribute matchid=%u, kind=%u, flags=%u\n",
diff --git a/lib/route/cls/ematch/cmp.c b/lib/route/cls/ematch/cmp.c
index 2997cdbc..2e380c39 100644
--- a/lib/route/cls/ematch/cmp.c
+++ b/lib/route/cls/ematch/cmp.c
@@ -20,6 +20,7 @@
#include <netlink-private/tc.h>
#include <netlink/netlink.h>
#include <netlink/route/cls/ematch.h>
+#include <netlink/route/cls/ematch/cmp.h>
#include <linux/tc_ematch/tc_em_cmp.h>
void rtnl_ematch_cmp_set(struct rtnl_ematch *e, struct tcf_em_cmp *cfg)
diff --git a/lib/route/cls/ematch/meta.c b/lib/route/cls/ematch/meta.c
index 44f11b92..a26ed4c8 100644
--- a/lib/route/cls/ematch/meta.c
+++ b/lib/route/cls/ematch/meta.c
@@ -21,6 +21,7 @@
#include <netlink/netlink.h>
#include <netlink/route/cls/ematch.h>
#include <netlink/route/cls/ematch/meta.h>
+#include <linux/tc_ematch/tc_em_meta.h>
struct rtnl_meta_value
{
@@ -51,7 +52,8 @@ static struct rtnl_meta_value *meta_alloc(uint8_t type, uint16_t id,
value->mv_shift = shift;
value->mv_len = len;
- memcpy(value + 1, data, len);
+ if (len)
+ memcpy(value + 1, data, len);
return value;
}
@@ -165,51 +167,51 @@ static int meta_parse(struct rtnl_ematch *e, void *data, size_t len)
}
static const struct trans_tbl meta_int[] = {
- __ADD(TCF_META_ID_RANDOM, random)
- __ADD(TCF_META_ID_LOADAVG_0, loadavg_0)
- __ADD(TCF_META_ID_LOADAVG_1, loadavg_1)
- __ADD(TCF_META_ID_LOADAVG_2, loadavg_2)
- __ADD(TCF_META_ID_DEV, dev)
- __ADD(TCF_META_ID_PRIORITY, prio)
- __ADD(TCF_META_ID_PROTOCOL, proto)
- __ADD(TCF_META_ID_PKTTYPE, pkttype)
- __ADD(TCF_META_ID_PKTLEN, pktlen)
- __ADD(TCF_META_ID_DATALEN, datalen)
- __ADD(TCF_META_ID_MACLEN, maclen)
- __ADD(TCF_META_ID_NFMARK, mark)
- __ADD(TCF_META_ID_TCINDEX, tcindex)
- __ADD(TCF_META_ID_RTCLASSID, rtclassid)
- __ADD(TCF_META_ID_RTIIF, rtiif)
- __ADD(TCF_META_ID_SK_FAMILY, sk_family)
- __ADD(TCF_META_ID_SK_STATE, sk_state)
- __ADD(TCF_META_ID_SK_REUSE, sk_reuse)
- __ADD(TCF_META_ID_SK_REFCNT, sk_refcnt)
- __ADD(TCF_META_ID_SK_RCVBUF, sk_rcvbuf)
- __ADD(TCF_META_ID_SK_SNDBUF, sk_sndbuf)
- __ADD(TCF_META_ID_SK_SHUTDOWN, sk_sutdown)
- __ADD(TCF_META_ID_SK_PROTO, sk_proto)
- __ADD(TCF_META_ID_SK_TYPE, sk_type)
- __ADD(TCF_META_ID_SK_RMEM_ALLOC, sk_rmem_alloc)
- __ADD(TCF_META_ID_SK_WMEM_ALLOC, sk_wmem_alloc)
- __ADD(TCF_META_ID_SK_WMEM_QUEUED, sk_wmem_queued)
- __ADD(TCF_META_ID_SK_RCV_QLEN, sk_rcv_qlen)
- __ADD(TCF_META_ID_SK_SND_QLEN, sk_snd_qlen)
- __ADD(TCF_META_ID_SK_ERR_QLEN, sk_err_qlen)
- __ADD(TCF_META_ID_SK_FORWARD_ALLOCS, sk_forward_allocs)
- __ADD(TCF_META_ID_SK_ALLOCS, sk_allocs)
- __ADD(TCF_META_ID_SK_ROUTE_CAPS, sk_route_caps)
- __ADD(TCF_META_ID_SK_HASH, sk_hash)
- __ADD(TCF_META_ID_SK_LINGERTIME, sk_lingertime)
- __ADD(TCF_META_ID_SK_ACK_BACKLOG, sk_ack_backlog)
- __ADD(TCF_META_ID_SK_MAX_ACK_BACKLOG, sk_max_ack_backlog)
- __ADD(TCF_META_ID_SK_PRIO, sk_prio)
- __ADD(TCF_META_ID_SK_RCVLOWAT, sk_rcvlowat)
- __ADD(TCF_META_ID_SK_RCVTIMEO, sk_rcvtimeo)
- __ADD(TCF_META_ID_SK_SNDTIMEO, sk_sndtimeo)
- __ADD(TCF_META_ID_SK_SENDMSG_OFF, sk_sendmsg_off)
- __ADD(TCF_META_ID_SK_WRITE_PENDING, sk_write_pending)
- __ADD(TCF_META_ID_VLAN_TAG, vlan)
- __ADD(TCF_META_ID_RXHASH, rxhash)
+ __ADD(TCF_META_ID_RANDOM, random),
+ __ADD(TCF_META_ID_LOADAVG_0, loadavg_0),
+ __ADD(TCF_META_ID_LOADAVG_1, loadavg_1),
+ __ADD(TCF_META_ID_LOADAVG_2, loadavg_2),
+ __ADD(TCF_META_ID_DEV, dev),
+ __ADD(TCF_META_ID_PRIORITY, prio),
+ __ADD(TCF_META_ID_PROTOCOL, proto),
+ __ADD(TCF_META_ID_PKTTYPE, pkttype),
+ __ADD(TCF_META_ID_PKTLEN, pktlen),
+ __ADD(TCF_META_ID_DATALEN, datalen),
+ __ADD(TCF_META_ID_MACLEN, maclen),
+ __ADD(TCF_META_ID_NFMARK, mark),
+ __ADD(TCF_META_ID_TCINDEX, tcindex),
+ __ADD(TCF_META_ID_RTCLASSID, rtclassid),
+ __ADD(TCF_META_ID_RTIIF, rtiif),
+ __ADD(TCF_META_ID_SK_FAMILY, sk_family),
+ __ADD(TCF_META_ID_SK_STATE, sk_state),
+ __ADD(TCF_META_ID_SK_REUSE, sk_reuse),
+ __ADD(TCF_META_ID_SK_REFCNT, sk_refcnt),
+ __ADD(TCF_META_ID_SK_RCVBUF, sk_rcvbuf),
+ __ADD(TCF_META_ID_SK_SNDBUF, sk_sndbuf),
+ __ADD(TCF_META_ID_SK_SHUTDOWN, sk_sutdown),
+ __ADD(TCF_META_ID_SK_PROTO, sk_proto),
+ __ADD(TCF_META_ID_SK_TYPE, sk_type),
+ __ADD(TCF_META_ID_SK_RMEM_ALLOC, sk_rmem_alloc),
+ __ADD(TCF_META_ID_SK_WMEM_ALLOC, sk_wmem_alloc),
+ __ADD(TCF_META_ID_SK_WMEM_QUEUED, sk_wmem_queued),
+ __ADD(TCF_META_ID_SK_RCV_QLEN, sk_rcv_qlen),
+ __ADD(TCF_META_ID_SK_SND_QLEN, sk_snd_qlen),
+ __ADD(TCF_META_ID_SK_ERR_QLEN, sk_err_qlen),
+ __ADD(TCF_META_ID_SK_FORWARD_ALLOCS, sk_forward_allocs),
+ __ADD(TCF_META_ID_SK_ALLOCS, sk_allocs),
+ __ADD(__TCF_META_ID_SK_ROUTE_CAPS, sk_route_caps),
+ __ADD(TCF_META_ID_SK_HASH, sk_hash),
+ __ADD(TCF_META_ID_SK_LINGERTIME, sk_lingertime),
+ __ADD(TCF_META_ID_SK_ACK_BACKLOG, sk_ack_backlog),
+ __ADD(TCF_META_ID_SK_MAX_ACK_BACKLOG, sk_max_ack_backlog),
+ __ADD(TCF_META_ID_SK_PRIO, sk_prio),
+ __ADD(TCF_META_ID_SK_RCVLOWAT, sk_rcvlowat),
+ __ADD(TCF_META_ID_SK_RCVTIMEO, sk_rcvtimeo),
+ __ADD(TCF_META_ID_SK_SNDTIMEO, sk_sndtimeo),
+ __ADD(TCF_META_ID_SK_SENDMSG_OFF, sk_sendmsg_off),
+ __ADD(TCF_META_ID_SK_WRITE_PENDING, sk_write_pending),
+ __ADD(TCF_META_ID_VLAN_TAG, vlan),
+ __ADD(TCF_META_ID_RXHASH, rxhash),
};
static char *int_id2str(int id, char *buf, size_t size)
@@ -218,8 +220,8 @@ static char *int_id2str(int id, char *buf, size_t size)
}
static const struct trans_tbl meta_var[] = {
- __ADD(TCF_META_ID_DEV,devname)
- __ADD(TCF_META_ID_SK_BOUND_IF,sk_bound_if)
+ __ADD(TCF_META_ID_DEV,devname),
+ __ADD(TCF_META_ID_SK_BOUND_IF,sk_bound_if),
};
static char *var_id2str(int id, char *buf, size_t size)
diff --git a/lib/route/cls/ematch/nbyte.c b/lib/route/cls/ematch/nbyte.c
index 88524893..2942c0da 100644
--- a/lib/route/cls/ematch/nbyte.c
+++ b/lib/route/cls/ematch/nbyte.c
@@ -21,6 +21,7 @@
#include <netlink/netlink.h>
#include <netlink/route/cls/ematch.h>
#include <netlink/route/cls/ematch/nbyte.h>
+#include <linux/tc_ematch/tc_em_nbyte.h>
struct nbyte_data
{
@@ -93,7 +94,7 @@ static int nbyte_parse(struct rtnl_ematch *e, void *data, size_t len)
if (!(n->pattern = calloc(1, plen)))
return -NLE_NOMEM;
- memcpy(n->pattern, data + hdrlen, plen);
+ memcpy(n->pattern, (char *) data + hdrlen, plen);
}
return 0;
diff --git a/lib/route/cls/ematch/text.c b/lib/route/cls/ematch/text.c
index e8cdcaec..4dcd4f05 100644
--- a/lib/route/cls/ematch/text.c
+++ b/lib/route/cls/ematch/text.c
@@ -21,6 +21,7 @@
#include <netlink/netlink.h>
#include <netlink/route/cls/ematch.h>
#include <netlink/route/cls/ematch/text.h>
+#include <linux/tc_ematch/tc_em_text.h>
struct text_data
{
@@ -91,6 +92,7 @@ void rtnl_ematch_text_set_algo(struct rtnl_ematch *e, const char *algo)
struct text_data *t = rtnl_ematch_data(e);
strncpy(t->cfg.algo, algo, sizeof(t->cfg.algo));
+ t->cfg.algo[sizeof(t->cfg.algo) - 1] = '\0';
}
char *rtnl_ematch_text_get_algo(struct rtnl_ematch *e)
@@ -115,7 +117,7 @@ static int text_parse(struct rtnl_ematch *e, void *data, size_t len)
if (!(t->pattern = calloc(1, t->cfg.pattern_len)))
return -NLE_NOMEM;
- memcpy(t->pattern, data + hdrlen, t->cfg.pattern_len);
+ memcpy(t->pattern, (char *) data + hdrlen, t->cfg.pattern_len);
}
return 0;
@@ -128,7 +130,7 @@ static void text_dump(struct rtnl_ematch *e, struct nl_dump_params *p)
nl_dump(p, "text(%s \"%s\"",
t->cfg.algo[0] ? t->cfg.algo : "no-algo",
- t->pattern ? : "no-pattern");
+ t->pattern ? t->pattern : "no-pattern");
if (t->cfg.from_layer || t->cfg.from_offset) {
nl_dump(p, " from %s",
diff --git a/lib/route/cls/ematch_grammar.l b/lib/route/cls/ematch_grammar.l
index 96ef1a0b..e97f9fef 100644
--- a/lib/route/cls/ematch_grammar.l
+++ b/lib/route/cls/ematch_grammar.l
@@ -15,7 +15,11 @@
#include <netlink/netlink.h>
#include <netlink/route/cls/ematch.h>
#include <netlink/route/cls/ematch/cmp.h>
+ #include <linux/tc_ematch/tc_em_cmp.h>
#include "ematch_syntax.h"
+
+ int ematch_get_column(yyscan_t);
+ void ematch_set_column(int, yyscan_t);
%}
%option 8bit
diff --git a/lib/route/cls/ematch_syntax.y b/lib/route/cls/ematch_syntax.y
index da210392..82d753d2 100644
--- a/lib/route/cls/ematch_syntax.y
+++ b/lib/route/cls/ematch_syntax.y
@@ -20,6 +20,8 @@
#include <netlink/route/cls/ematch/nbyte.h>
#include <netlink/route/cls/ematch/text.h>
#include <netlink/route/cls/ematch/meta.h>
+#include <linux/tc_ematch/tc_em_meta.h>
+#include <linux/tc_ematch/tc_em_cmp.h>
#define META_ALLOC rtnl_meta_value_alloc_id
#define META_ID(name) TCF_META_ID_##name
@@ -53,9 +55,9 @@ extern int ematch_lex(YYSTYPE *, void *);
static void yyerror(void *scanner, char **errp, struct nl_list_head *root, const char *msg)
{
if (msg)
- *errp = strdup(msg);
- else
- *errp = NULL;
+ *errp = strdup(msg);
+ else
+ *errp = NULL;
}
%}
@@ -374,7 +376,7 @@ meta_int_id:
| META_SK_ERR_QLEN { $$ = META_ID(SK_ERR_QLEN); }
| META_SK_FORWARD_ALLOCS { $$ = META_ID(SK_FORWARD_ALLOCS); }
| META_SK_ALLOCS { $$ = META_ID(SK_ALLOCS); }
- | META_SK_ROUTE_CAPS { $$ = META_ID(SK_ROUTE_CAPS); }
+ | META_SK_ROUTE_CAPS { $$ = __TCF_META_ID_SK_ROUTE_CAPS; }
| META_SK_HASH { $$ = META_ID(SK_HASH); }
| META_SK_LINGERTIME { $$ = META_ID(SK_LINGERTIME); }
| META_SK_ACK_BACKLOG { $$ = META_ID(SK_ACK_BACKLOG); }
diff --git a/lib/route/cls/mall.c b/lib/route/cls/mall.c
new file mode 100644
index 00000000..e13ee92f
--- /dev/null
+++ b/lib/route/cls/mall.c
@@ -0,0 +1,305 @@
+/*
+ * lib/route/cls/mall.c match-all classifier
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2017 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
+ */
+
+/**
+ * @ingroup cls
+ * @defgroup cls_mall Match-all Classifier
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/classifier.h>
+#include <netlink/route/cls/matchall.h>
+#include <netlink/route/action.h>
+
+
+#define MALL_ATTR_CLASSID 0x01
+#define MALL_ATTR_FLAGS 0x02
+#define MALL_ATTR_ACTION 0x03
+
+
+static struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = {
+ [TCA_MATCHALL_CLASSID] = { .type = NLA_U32 },
+ [TCA_MATCHALL_FLAGS] = { .type = NLA_U32 },
+};
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+int rtnl_mall_set_classid(struct rtnl_cls *cls, uint32_t classid)
+{
+ struct rtnl_mall *mall;
+ if (!(mall = rtnl_tc_data(TC_CAST(cls))))
+ return -NLE_NOMEM;
+
+ mall->m_classid = classid;
+ mall->m_mask |= MALL_ATTR_CLASSID;
+
+ return 0;
+}
+
+int rtnl_mall_get_classid(struct rtnl_cls *cls, uint32_t *classid)
+{
+ struct rtnl_mall *mall;
+
+ if (!(mall = rtnl_tc_data_peek(TC_CAST(cls))))
+ return -NLE_INVAL;
+
+ if (!(mall->m_mask & MALL_ATTR_CLASSID))
+ return -NLE_INVAL;
+
+ *classid = mall->m_classid;
+ return 0;
+}
+
+int rtnl_mall_set_flags(struct rtnl_cls *cls, uint32_t flags)
+{
+ struct rtnl_mall *mall;
+
+ if (!(mall = rtnl_tc_data(TC_CAST(cls))))
+ return -NLE_NOMEM;
+
+ mall->m_flags = flags;
+ mall->m_mask |= MALL_ATTR_FLAGS;
+
+ return 0;
+}
+
+int rtnl_mall_get_flags(struct rtnl_cls *cls, uint32_t *flags)
+{
+ struct rtnl_mall *mall;
+
+ if (!(mall = rtnl_tc_data_peek(TC_CAST(cls))))
+ return -NLE_INVAL;
+
+ if (!(mall->m_mask & MALL_ATTR_FLAGS))
+ return -NLE_INVAL;
+
+ *flags = mall->m_flags;
+ return 0;
+}
+
+int rtnl_mall_append_action(struct rtnl_cls *cls, struct rtnl_act *act)
+{
+ struct rtnl_mall *mall;
+ int err;
+
+ if (!act)
+ return 0;
+
+ if (!(mall = rtnl_tc_data(TC_CAST(cls))))
+ return -NLE_NOMEM;
+
+ mall->m_mask |= MALL_ATTR_ACTION;
+ err = rtnl_act_append(&mall->m_act, act);
+ if (err)
+ return err;
+
+ rtnl_act_get(act);
+ return 0;
+}
+
+struct rtnl_act *rtnl_mall_get_first_action(struct rtnl_cls *cls)
+{
+ struct rtnl_mall *mall;
+ struct rtnl_act *act;
+
+ if (!(mall = rtnl_tc_data(TC_CAST(cls))))
+ return NULL;
+
+ if (!(mall->m_mask & MALL_ATTR_ACTION))
+ return NULL;
+
+ act = mall->m_act;
+ rtnl_act_get(act);
+
+ return act;
+}
+
+int rtnl_mall_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
+{
+ struct rtnl_mall *mall;
+ int ret;
+
+ if (!act)
+ return 0;
+
+ if (!(mall = rtnl_tc_data(TC_CAST(cls))))
+ return -NLE_NOMEM;
+
+ if (!(mall->m_mask & MALL_ATTR_ACTION))
+ return -NLE_INVAL;
+
+ ret = rtnl_act_remove(&mall->m_act, act);
+ if (ret < 0)
+ return ret;
+
+ rtnl_act_put(act);
+
+ return 0;
+}
+
+/** @} */
+
+static void mall_free_data(struct rtnl_tc *tc, void *data)
+{
+ struct rtnl_mall *mall = data;
+
+ if (mall->m_act)
+ rtnl_act_put_all(&mall->m_act);
+}
+
+static int mall_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct rtnl_mall *mall = data;
+ struct nlattr *tb[TCA_MATCHALL_MAX + 1];
+ int err;
+
+ err = tca_parse(tb, TCA_MATCHALL_MAX, tc, mall_policy);
+ if (err < 0)
+ return err;
+
+ if (tb[TCA_MATCHALL_CLASSID]) {
+ mall->m_classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
+ mall->m_mask |= MALL_ATTR_CLASSID;
+ }
+
+ if (tb[TCA_MATCHALL_FLAGS]) {
+ mall->m_flags = nla_get_u32(tb[TCA_MATCHALL_FLAGS]);
+ mall->m_mask |= MALL_ATTR_FLAGS;
+ }
+
+ if (tb[TCA_MATCHALL_ACT]) {
+ mall->m_mask |= MALL_ATTR_ACTION;
+ err = rtnl_act_parse(&mall->m_act, tb[TCA_MATCHALL_ACT]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int mall_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct rtnl_mall *mall = data;
+
+ if (!mall)
+ return 0;
+
+ if (mall->m_mask & MALL_ATTR_CLASSID)
+ NLA_PUT_U32(msg, TCA_MATCHALL_CLASSID, mall->m_classid);
+
+ if (mall->m_mask & MALL_ATTR_FLAGS)
+ NLA_PUT_U32(msg, TCA_MATCHALL_FLAGS, mall->m_flags);
+
+ if (mall->m_mask & MALL_ATTR_ACTION) {
+ int err;
+
+ err = rtnl_act_fill(msg, TCA_MATCHALL_ACT, mall->m_act);
+ if (err)
+ return err;
+ }
+
+ return 0;
+
+ nla_put_failure:
+ return -NLE_NOMEM;
+}
+
+static int mall_clone(void *_dst, void *_src)
+{
+ struct rtnl_mall *dst = _dst, *src = _src;
+ struct rtnl_act *next, *new;
+ int err;
+
+ if (src->m_act) {
+ if (!(dst->m_act = rtnl_act_alloc()))
+ return -NLE_NOMEM;
+
+ /* action nl list next and prev pointers must be updated */
+ nl_init_list_head(&dst->m_act->ce_list);
+
+ memcpy(dst->m_act, src->m_act, sizeof(struct rtnl_act));
+ next = rtnl_act_next(src->m_act);
+ while (next) {
+ new = (struct rtnl_act *) nl_object_clone((struct nl_object *) next);
+ if (!new)
+ return -NLE_NOMEM;
+
+ err = rtnl_act_append(&dst->m_act, new);
+ if (err < 0)
+ return err;
+
+ next = rtnl_act_next(next);
+ }
+ }
+
+ return 0;
+}
+
+static void mall_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_mall *mall = data;
+ char buf[32];
+
+ if (!mall)
+ return;
+
+ if (mall->m_mask & MALL_ATTR_CLASSID)
+ nl_dump(p, " target %s",
+ rtnl_tc_handle2str(mall->m_classid, buf, sizeof(buf)));
+}
+
+static void mall_dump_details(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_mall *mall = data;
+
+ if (!mall)
+ return;
+
+ nl_dump(p, "no details for match-all");
+}
+
+static struct rtnl_tc_ops mall_ops = {
+ .to_kind = "matchall",
+ .to_type = RTNL_TC_TYPE_CLS,
+ .to_size = sizeof(struct rtnl_mall),
+ .to_msg_parser = mall_msg_parser,
+ .to_free_data = mall_free_data,
+ .to_clone = mall_clone,
+ .to_msg_fill = mall_msg_fill,
+ .to_dump = {
+ [NL_DUMP_LINE] = mall_dump_line,
+ [NL_DUMP_DETAILS] = mall_dump_details,
+ },
+};
+
+static void __init mall_init(void)
+{
+ rtnl_tc_register(&mall_ops);
+}
+
+static void __exit mall_exit(void)
+{
+ rtnl_tc_unregister(&mall_ops);
+}
+
+/** @} */
diff --git a/lib/route/cls/police.c b/lib/route/cls/police.c
index 1f5d2844..14b5608d 100644
--- a/lib/route/cls/police.c
+++ b/lib/route/cls/police.c
@@ -23,12 +23,12 @@
*/
static const struct trans_tbl police_types[] = {
- __ADD(TC_POLICE_UNSPEC,unspec)
- __ADD(TC_POLICE_OK,ok)
- __ADD(TC_POLICE_RECLASSIFY,reclassify)
- __ADD(TC_POLICE_SHOT,shot)
+ __ADD(TC_POLICE_UNSPEC,unspec),
+ __ADD(TC_POLICE_OK,ok),
+ __ADD(TC_POLICE_RECLASSIFY,reclassify),
+ __ADD(TC_POLICE_SHOT,shot),
#ifdef TC_POLICE_PIPE
- __ADD(TC_POLICE_PIPE,pipe)
+ __ADD(TC_POLICE_PIPE,pipe),
#endif
};
diff --git a/lib/route/cls/u32.c b/lib/route/cls/u32.c
index 0a4e83cf..f06bc242 100644
--- a/lib/route/cls/u32.c
+++ b/lib/route/cls/u32.c
@@ -38,6 +38,7 @@
#define U32_ATTR_ACTION 0x040
#define U32_ATTR_POLICE 0x080
#define U32_ATTR_INDEV 0x100
+#define U32_ATTR_MARK 0x200
/** @endcond */
static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
@@ -53,6 +54,14 @@ static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
return u32_selector(u);
}
+static inline struct tc_u32_mark *u32_mark_alloc(struct rtnl_u32 *u)
+{
+ if (!u->cu_mark)
+ u->cu_mark = nl_data_alloc(NULL, sizeof(struct tc_u32_mark));
+
+ return (struct tc_u32_mark *) u->cu_mark->d_data;
+}
+
static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
[TCA_U32_DIVISOR] = { .type = NLA_U32 },
[TCA_U32_HASH] = { .type = NLA_U32 },
@@ -62,6 +71,7 @@ static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
.maxlen = IFNAMSIZ },
[TCA_U32_SEL] = { .minlen = sizeof(struct tc_u32_sel) },
[TCA_U32_PCNT] = { .minlen = sizeof(struct tc_u32_pcnt) },
+ [TCA_U32_MARK] = { .minlen = sizeof(struct tc_u32_mark) }
};
static int u32_msg_parser(struct rtnl_tc *tc, void *data)
@@ -86,6 +96,13 @@ static int u32_msg_parser(struct rtnl_tc *tc, void *data)
u->cu_mask |= U32_ATTR_SELECTOR;
}
+ if (tb[TCA_U32_MARK]) {
+ u->cu_mark = nl_data_alloc_attr(tb[TCA_U32_MARK]);
+ if (!u->cu_mark)
+ goto errout_nomem;
+ u->cu_mask |= U32_ATTR_MARK;
+ }
+
if (tb[TCA_U32_HASH]) {
u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
u->cu_mask |= U32_ATTR_HASH;
@@ -123,7 +140,7 @@ static int u32_msg_parser(struct rtnl_tc *tc, void *data)
err = -NLE_MISSING_ATTR;
goto errout;
}
-
+
sel = u->cu_selector->d_data;
pcnt_size = sizeof(struct tc_u32_pcnt) +
(sel->nkeys * sizeof(uint64_t));
@@ -157,6 +174,7 @@ static void u32_free_data(struct rtnl_tc *tc, void *data)
if (u->cu_act)
rtnl_act_put_all(&u->cu_act);
+ nl_data_free(u->cu_mark);
nl_data_free(u->cu_selector);
nl_data_free(u->cu_police);
nl_data_free(u->cu_pcnt);
@@ -170,6 +188,10 @@ static int u32_clone(void *_dst, void *_src)
!(dst->cu_selector = nl_data_clone(src->cu_selector)))
return -NLE_NOMEM;
+ if (src->cu_mark &&
+ !(dst->cu_mark = nl_data_clone(src->cu_mark)))
+ return -NLE_NOMEM;
+
if (src->cu_act) {
if (!(dst->cu_act = rtnl_act_alloc()))
return -NLE_NOMEM;
@@ -191,7 +213,7 @@ static void u32_dump_line(struct rtnl_tc *tc, void *data,
{
struct rtnl_u32 *u = data;
char buf[32];
-
+
if (!u)
return;
@@ -239,10 +261,10 @@ static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
nl_dump(p, ">");
}
-
-
+
+
for (i = 0; i < sel->nkeys; i++) {
- key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
+ key = &sel->keys[i];
nl_dump(p, "\n");
nl_dump_line(p, " match key at %s%u ",
@@ -265,31 +287,44 @@ static void u32_dump_details(struct rtnl_tc *tc, void *data,
struct nl_dump_params *p)
{
struct rtnl_u32 *u = data;
- struct tc_u32_sel *s;
+ struct tc_u32_sel *s = NULL;
+ struct tc_u32_mark *m;
if (!u)
return;
- if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
- nl_dump(p, "no-selector\n");
+ if (!(u->cu_mask & (U32_ATTR_SELECTOR & U32_ATTR_MARK))) {
+ nl_dump(p, "no-selector no-mark\n");
return;
}
-
- s = u->cu_selector->d_data;
- nl_dump(p, "nkeys %u ", s->nkeys);
+ if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
+ nl_dump(p, "no-selector");
+ } else {
+ s = u->cu_selector->d_data;
+ nl_dump(p, "nkeys %u", s->nkeys);
+ }
+
+ if (!(u->cu_mask & U32_ATTR_MARK)) {
+ nl_dump(p, " no-mark");
+ } else {
+ m = u->cu_mark->d_data;
+ nl_dump(p, " mark 0x%u 0x%u", m->val, m->mask);
+ }
if (u->cu_mask & U32_ATTR_HASH)
- nl_dump(p, "ht key 0x%x hash 0x%u",
+ nl_dump(p, " ht key 0x%x hash 0x%u",
TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
if (u->cu_mask & U32_ATTR_LINK)
- nl_dump(p, "link %u ", u->cu_link);
+ nl_dump(p, " link %u", u->cu_link);
if (u->cu_mask & U32_ATTR_INDEV)
- nl_dump(p, "indev %s ", u->cu_indev);
+ nl_dump(p, " indev %s", u->cu_indev);
+
+ if (u->cu_mask & U32_ATTR_SELECTOR)
+ print_selector(p, s, u);
- print_selector(p, s, u);
nl_dump(p, "\n");
}
@@ -315,7 +350,7 @@ static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
if (!u)
return 0;
-
+
if (u->cu_mask & U32_ATTR_DIVISOR)
NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
@@ -331,6 +366,9 @@ static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
if (u->cu_mask & U32_ATTR_SELECTOR)
NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
+ if (u->cu_mask & U32_ATTR_MARK)
+ NLA_PUT_DATA(msg, TCA_U32_MARK, u->cu_mark);
+
if (u->cu_mask & U32_ATTR_ACTION) {
int err;
@@ -363,20 +401,34 @@ void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
rtnl_tc_set_handle((struct rtnl_tc *) cls, handle );
}
-
+
int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
{
struct rtnl_u32 *u;
if (!(u = rtnl_tc_data(TC_CAST(cls))))
return -NLE_NOMEM;
-
+
u->cu_classid = classid;
u->cu_mask |= U32_ATTR_CLASSID;
return 0;
}
+int rtnl_u32_get_classid(struct rtnl_cls *cls, uint32_t *classid)
+{
+ struct rtnl_u32 *u;
+
+ if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
+ return -NLE_INVAL;
+
+ if (!(u->cu_mask & U32_ATTR_CLASSID))
+ return -NLE_INVAL;
+
+ *classid = u->cu_classid;
+ return 0;
+}
+
int rtnl_u32_set_divisor(struct rtnl_cls *cls, uint32_t divisor)
{
struct rtnl_u32 *u;
@@ -417,7 +469,6 @@ int rtnl_u32_set_hashmask(struct rtnl_cls *cls, uint32_t hashmask, uint32_t offs
{
struct rtnl_u32 *u;
struct tc_u32_sel *sel;
- int err;
hashmask = htonl(hashmask);
@@ -428,22 +479,17 @@ int rtnl_u32_set_hashmask(struct rtnl_cls *cls, uint32_t hashmask, uint32_t offs
if (!sel)
return -NLE_NOMEM;
- err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
- if(err < 0)
- return err;
-
- sel = u32_selector(u);
-
sel->hmask = hashmask;
sel->hoff = offset;
return 0;
}
-int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
+int rtnl_u32_set_selector(struct rtnl_cls *cls, int offoff, uint32_t offmask, char offshift, uint16_t off, char flags)
{
struct rtnl_u32 *u;
struct tc_u32_sel *sel;
- int err;
+
+ offmask = ntohs(offmask);
if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
return -NLE_NOMEM;
@@ -452,11 +498,26 @@ int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
if (!sel)
return -NLE_NOMEM;
- err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
- if(err < 0)
- return err;
+ sel->offoff = offoff;
+ sel->offmask = offmask;
+ sel->offshift = offshift;
+ sel->flags |= TC_U32_VAROFFSET;
+ sel->off = off;
+ sel->flags |= flags;
+ return 0;
+}
- sel = u32_selector(u);
+int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
+{
+ struct rtnl_u32 *u;
+ struct tc_u32_sel *sel;
+
+ if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
+ return -NLE_NOMEM;
+
+ sel = u32_selector_alloc(u);
+ if (!sel)
+ return -NLE_NOMEM;
sel->flags |= TC_U32_TERMINAL;
return 0;
@@ -465,6 +526,7 @@ int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
int rtnl_u32_add_action(struct rtnl_cls *cls, struct rtnl_act *act)
{
struct rtnl_u32 *u;
+ int err;
if (!act)
return 0;
@@ -473,9 +535,25 @@ int rtnl_u32_add_action(struct rtnl_cls *cls, struct rtnl_act *act)
return -NLE_NOMEM;
u->cu_mask |= U32_ATTR_ACTION;
+ if ((err = rtnl_act_append(&u->cu_act, act)))
+ return err;
+
/* In case user frees it */
rtnl_act_get(act);
- return rtnl_act_append(&u->cu_act, act);
+ return 0;
+}
+
+struct rtnl_act* rtnl_u32_get_action(struct rtnl_cls *cls)
+{
+ struct rtnl_u32 *u;
+
+ if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
+ return NULL;
+
+ if (!(u->cu_mask & U32_ATTR_ACTION))
+ return NULL;
+
+ return u->cu_act;
}
int rtnl_u32_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
@@ -554,6 +632,9 @@ int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
if (!sel)
return -NLE_NOMEM;
+ if (sel->nkeys == UCHAR_MAX)
+ return -NLE_NOMEM;
+
err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
if (err < 0)
return err;
@@ -571,6 +652,46 @@ int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
return 0;
}
+int rtnl_u32_add_mark(struct rtnl_cls *cls, uint32_t val, uint32_t mask)
+{
+ struct tc_u32_mark *mark;
+ struct rtnl_u32 *u;
+
+ if (!(u = rtnl_tc_data(TC_CAST(cls))))
+ return -NLE_NOMEM;
+
+ mark = u32_mark_alloc(u);
+ if (!mark)
+ return -NLE_NOMEM;
+
+ mark->mask = mask;
+ mark->val = val;
+
+ u->cu_mask |= U32_ATTR_MARK;
+
+ return 0;
+}
+
+int rtnl_u32_del_mark(struct rtnl_cls *cls)
+{
+ struct rtnl_u32 *u;
+
+ if (!(u = rtnl_tc_data(TC_CAST(cls))))
+ return -NLE_NOMEM;
+
+ if (!(u->cu_mask))
+ return -NLE_INVAL;
+
+ if (!(u->cu_mask & U32_ATTR_MARK))
+ return -NLE_INVAL;
+
+ nl_data_free(u->cu_mark);
+ u->cu_mark = NULL;
+ u->cu_mask &= ~U32_ATTR_MARK;
+
+ return 0;
+}
+
/**
* Get the 32-bit key from the selector
*
@@ -594,7 +715,6 @@ int rtnl_u32_get_key(struct rtnl_cls *cls, uint8_t index,
if (!(u->cu_mask & U32_ATTR_SELECTOR))
return -NLE_INVAL;
- /* the selector might have been moved by realloc */
sel = u32_selector(u);
if (index >= sel->nkeys)
return -NLE_RANGE;
diff --git a/lib/route/link.c b/lib/route/link.c
index 3d31ffcb..df01a71a 100644
--- a/lib/route/link.c
+++ b/lib/route/link.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/link.c Links (Interfaces)
*
@@ -28,6 +29,8 @@
#include <netlink/route/rtnl.h>
#include <netlink/route/link.h>
#include <netlink-private/route/link/api.h>
+#include <netlink-private/route/link/sriov.h>
+#include <netlink-private/utils.h>
/** @cond SKIP */
#define LINK_ATTR_MTU (1 << 0)
@@ -61,11 +64,31 @@
#define LINK_ATTR_PHYS_PORT_ID (1 << 28)
#define LINK_ATTR_NS_FD (1 << 29)
#define LINK_ATTR_NS_PID (1 << 30)
+/* 31 used by 32-bit api */
+#define LINK_ATTR_LINK_NETNSID ((uint64_t) 1 << 32)
+#define LINK_ATTR_VF_LIST ((uint64_t) 1 << 33)
+#define LINK_ATTR_CARRIER_CHANGES ((uint64_t) 1 << 34)
+#define LINK_ATTR_PHYS_PORT_NAME ((uint64_t) 1 << 35)
+#define LINK_ATTR_PHYS_SWITCH_ID ((uint64_t) 1 << 36)
+#define LINK_ATTR_GSO_MAX_SEGS ((uint64_t) 1 << 37)
+#define LINK_ATTR_GSO_MAX_SIZE ((uint64_t) 1 << 38)
+#define LINK_ATTR_LINKINFO_SLAVE_KIND ((uint64_t) 1 << 39)
static struct nl_cache_ops rtnl_link_ops;
static struct nl_object_ops link_obj_ops;
/** @endcond */
+struct rtnl_link *link_lookup(struct nl_cache *cache, int ifindex)
+{
+ if (!cache) {
+ cache = __nl_cache_mngt_require("route/link");
+ if (!cache)
+ return NULL;
+ }
+
+ return rtnl_link_get(cache, ifindex);
+}
+
static struct rtnl_link_af_ops *af_lookup_and_alloc(struct rtnl_link *link,
int family)
{
@@ -95,6 +118,17 @@ static int af_free(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
return 0;
}
+static int af_request_type(int af_type, struct rtnl_link *changes)
+{
+ struct rtnl_link_af_ops *ops;
+
+ ops = rtnl_link_af_ops_lookup(af_type);
+ if (ops && ops->ao_override_rtm(changes))
+ return RTM_SETLINK;
+
+ return RTM_NEWLINK;
+}
+
static int af_clone(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
void *data, void *arg)
{
@@ -111,19 +145,45 @@ static int af_fill(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
void *data, void *arg)
{
struct nl_msg *msg = arg;
- struct nlattr *af_attr;
+ struct nlattr *af_attr = NULL;
int err;
if (!ops->ao_fill_af)
return 0;
- if (!(af_attr = nla_nest_start(msg, ops->ao_family)))
- return -NLE_MSGSIZE;
+ if (!ops->ao_fill_af_no_nest)
+ if (!(af_attr = nla_nest_start(msg, ops->ao_family)))
+ return -NLE_MSGSIZE;
if ((err = ops->ao_fill_af(link, arg, data)) < 0)
return err;
- nla_nest_end(msg, af_attr);
+ if (!ops->ao_fill_af_no_nest)
+ nla_nest_end(msg, af_attr);
+
+ return 0;
+}
+
+static int af_fill_pi(struct rtnl_link *link, struct rtnl_link_af_ops *ops,
+ void *data, void *arg)
+{
+ struct nl_msg *msg = arg;
+ struct nlattr *pi_attr;
+ int err, pi_type = IFLA_PROTINFO;
+
+ if (!ops->ao_fill_pi)
+ return 0;
+
+ if (ops->ao_fill_pi_flags > 0)
+ pi_type |= ops->ao_fill_pi_flags;
+
+ if (!(pi_attr = nla_nest_start(msg, pi_type)))
+ return -NLE_MSGSIZE;
+
+ if ((err = ops->ao_fill_pi(link, arg, data)) < 0)
+ return err;
+
+ nla_nest_end(msg, pi_attr);
return 0;
}
@@ -208,10 +268,7 @@ static void link_free_data(struct nl_object *c)
struct rtnl_link *link = nl_object_priv(c);
if (link) {
- struct rtnl_link_info_ops *io;
-
- if ((io = link->l_info_ops) != NULL)
- release_link_info(link);
+ release_link_info(link);
/* proto info af reference */
rtnl_link_af_ops_put(link->l_af_ops);
@@ -221,10 +278,15 @@ static void link_free_data(struct nl_object *c)
free(link->l_ifalias);
free(link->l_info_kind);
+ free(link->l_info_slave_kind);
do_foreach_af(link, af_free, NULL);
nl_data_free(link->l_phys_port_id);
+ nl_data_free(link->l_phys_switch_id);
+
+ if (link->ce_mask & LINK_ATTR_VF_LIST)
+ rtnl_link_sriov_free_data(link);
}
}
@@ -250,6 +312,10 @@ static int link_clone(struct nl_object *_dst, struct nl_object *_src)
if (!(dst->l_info_kind = strdup(src->l_info_kind)))
return -NLE_NOMEM;
+ if (src->l_info_slave_kind)
+ if (!(dst->l_info_slave_kind = strdup(src->l_info_slave_kind)))
+ return -NLE_NOMEM;
+
if (src->l_info_ops && src->l_info_ops->io_clone) {
err = src->l_info_ops->io_clone(dst, src);
if (err < 0)
@@ -263,6 +329,14 @@ static int link_clone(struct nl_object *_dst, struct nl_object *_src)
if (!(dst->l_phys_port_id = nl_data_clone(src->l_phys_port_id)))
return -NLE_NOMEM;
+ if (src->l_phys_switch_id)
+ if (!(dst->l_phys_switch_id = nl_data_clone(src->l_phys_switch_id)))
+ return -NLE_NOMEM;
+
+ if (src->ce_mask & LINK_ATTR_VF_LIST)
+ if ((err = rtnl_link_sriov_clone(dst, src)) < 0)
+ return err;
+
return 0;
}
@@ -279,18 +353,24 @@ struct nla_policy rtln_link_policy[IFLA_MAX+1] = {
[IFLA_LINKINFO] = { .type = NLA_NESTED },
[IFLA_QDISC] = { .type = NLA_STRING,
.maxlen = IFQDISCSIZ },
- [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) },
- [IFLA_STATS64] = { .minlen = sizeof(struct rtnl_link_stats64)},
+ [IFLA_STATS] = { .minlen = _nl_offsetofend (struct rtnl_link_stats, tx_compressed) },
+ [IFLA_STATS64] = { .minlen = _nl_offsetofend (struct rtnl_link_stats64, tx_compressed) },
[IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) },
[IFLA_IFALIAS] = { .type = NLA_STRING, .maxlen = IFALIASZ },
[IFLA_NUM_VF] = { .type = NLA_U32 },
+ [IFLA_VFINFO_LIST] = { .type = NLA_NESTED },
[IFLA_AF_SPEC] = { .type = NLA_NESTED },
[IFLA_PROMISCUITY] = { .type = NLA_U32 },
[IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 },
[IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 },
+ [IFLA_GSO_MAX_SEGS] = { .type = NLA_U32 },
+ [IFLA_GSO_MAX_SIZE] = { .type = NLA_U32 },
[IFLA_GROUP] = { .type = NLA_U32 },
[IFLA_CARRIER] = { .type = NLA_U8 },
+ [IFLA_CARRIER_CHANGES] = { .type = NLA_U32 },
[IFLA_PHYS_PORT_ID] = { .type = NLA_UNSPEC },
+ [IFLA_PHYS_PORT_NAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ },
+ [IFLA_PHYS_SWITCH_ID] = { .type = NLA_UNSPEC },
[IFLA_NET_NS_PID] = { .type = NLA_U32 },
[IFLA_NET_NS_FD] = { .type = NLA_U32 },
};
@@ -339,6 +419,14 @@ int rtnl_link_info_parse(struct rtnl_link *link, struct nlattr **tb)
link->l_stats[RTNL_LINK_RX_COMPRESSED] = st->rx_compressed;
link->l_stats[RTNL_LINK_TX_COMPRESSED] = st->tx_compressed;
+ /* beware: @st might not be the full struct, only fields up to
+ * tx_compressed are present. See _nl_offsetofend() above. */
+
+ if (nla_len(tb[IFLA_STATS]) >= _nl_offsetofend (struct rtnl_link_stats, rx_nohandler))
+ link->l_stats[RTNL_LINK_RX_NOHANDLER] = st->rx_nohandler;
+ else
+ link->l_stats[RTNL_LINK_RX_NOHANDLER] = 0;
+
link->ce_mask |= LINK_ATTR_STATS;
}
@@ -350,11 +438,10 @@ int rtnl_link_info_parse(struct rtnl_link *link, struct nlattr **tb)
* Therefore, copy the data to the stack and access it from
* there, where it will be aligned to 8.
*/
- struct rtnl_link_stats64 st;
+ struct rtnl_link_stats64 st = { 0 };
+
+ nla_memcpy(&st, tb[IFLA_STATS64], sizeof (st));
- nla_memcpy(&st, tb[IFLA_STATS64],
- sizeof(struct rtnl_link_stats64));
-
link->l_stats[RTNL_LINK_RX_PACKETS] = st.rx_packets;
link->l_stats[RTNL_LINK_TX_PACKETS] = st.tx_packets;
link->l_stats[RTNL_LINK_RX_BYTES] = st.rx_bytes;
@@ -382,6 +469,11 @@ int rtnl_link_info_parse(struct rtnl_link *link, struct nlattr **tb)
link->l_stats[RTNL_LINK_RX_COMPRESSED] = st.rx_compressed;
link->l_stats[RTNL_LINK_TX_COMPRESSED] = st.tx_compressed;
+ /* beware: @st might not be the full struct, only fields up to
+ * tx_compressed are present. See _nl_offsetofend() above. */
+
+ link->l_stats[RTNL_LINK_RX_NOHANDLER] = st.rx_nohandler;
+
link->ce_mask |= LINK_ATTR_STATS;
}
@@ -419,6 +511,11 @@ int rtnl_link_info_parse(struct rtnl_link *link, struct nlattr **tb)
link->ce_mask |= LINK_ATTR_LINK;
}
+ if (tb[IFLA_LINK_NETNSID]) {
+ link->l_link_netnsid = nla_get_s32(tb[IFLA_LINK_NETNSID]);
+ link->ce_mask |= LINK_ATTR_LINK_NETNSID;
+ }
+
if (tb[IFLA_WEIGHT]) {
link->l_weight = nla_get_u32(tb[IFLA_WEIGHT]);
link->ce_mask |= LINK_ATTR_WEIGHT;
@@ -430,7 +527,7 @@ int rtnl_link_info_parse(struct rtnl_link *link, struct nlattr **tb)
}
if (tb[IFLA_MAP]) {
- nla_memcpy(&link->l_map, tb[IFLA_MAP],
+ nla_memcpy(&link->l_map, tb[IFLA_MAP],
sizeof(struct rtnl_link_ifmap));
link->ce_mask |= LINK_ATTR_MAP;
}
@@ -445,6 +542,11 @@ int rtnl_link_info_parse(struct rtnl_link *link, struct nlattr **tb)
link->ce_mask |= LINK_ATTR_CARRIER;
}
+ if (tb[IFLA_CARRIER_CHANGES]) {
+ link->l_carrier_changes = nla_get_u32(tb[IFLA_CARRIER_CHANGES]);
+ link->ce_mask |= LINK_ATTR_CARRIER_CHANGES;
+ }
+
if (tb[IFLA_OPERSTATE]) {
link->l_operstate = nla_get_u8(tb[IFLA_OPERSTATE]);
link->ce_mask |= LINK_ATTR_OPERSTATE;
@@ -482,6 +584,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
struct ifinfomsg *ifi;
struct nlattr *tb[IFLA_MAX+1];
struct rtnl_link_af_ops *af_ops = NULL;
+ struct rtnl_link_af_ops *af_ops_family;
int err, family;
struct nla_policy real_link_policy[IFLA_MAX+1];
@@ -495,8 +598,10 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
link->ce_msgtype = n->nlmsg_type;
- if (!nlmsg_valid_hdr(n, sizeof(*ifi)))
- return -NLE_MSG_TOOSHORT;
+ if (!nlmsg_valid_hdr(n, sizeof(*ifi))) {
+ err = -NLE_MSG_TOOSHORT;
+ goto errout;
+ }
ifi = nlmsg_data(n);
link->l_family = family = ifi->ifi_family;
@@ -505,10 +610,10 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
link->l_flags = ifi->ifi_flags;
link->l_change = ifi->ifi_change;
link->ce_mask = (LINK_ATTR_IFNAME | LINK_ATTR_FAMILY |
- LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
- LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
+ LINK_ATTR_ARPTYPE| LINK_ATTR_IFINDEX |
+ LINK_ATTR_FLAGS | LINK_ATTR_CHANGE);
- if ((af_ops = af_lookup_and_alloc(link, family))) {
+ if ((af_ops_family = af_ops = af_lookup_and_alloc(link, family))) {
if (af_ops->ao_protinfo_policy) {
memcpy(&real_link_policy[IFLA_PROTINFO],
af_ops->ao_protinfo_policy,
@@ -520,15 +625,21 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
err = nlmsg_parse(n, sizeof(*ifi), tb, IFLA_MAX, real_link_policy);
if (err < 0)
- return err;
+ goto errout;
err = rtnl_link_info_parse(link, tb);
if (err < 0)
- return err;
+ goto errout;
if (tb[IFLA_NUM_VF]) {
link->l_num_vf = nla_get_u32(tb[IFLA_NUM_VF]);
link->ce_mask |= LINK_ATTR_NUM_VF;
+ if (link->l_num_vf && tb[IFLA_VFINFO_LIST]) {
+ if ((err = rtnl_link_sriov_parse_vflist(link, tb)) < 0) {
+ goto errout;
+ }
+ link->ce_mask |= LINK_ATTR_VF_LIST;
+ }
}
if (tb[IFLA_LINKINFO]) {
@@ -541,7 +652,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
if (li[IFLA_INFO_KIND]) {
struct rtnl_link_info_ops *ops;
- char *kind = nla_get_string(li[IFLA_INFO_KIND]);
+ const char *kind = nla_get_string(li[IFLA_INFO_KIND]);
int af;
err = rtnl_link_set_type(link, kind);
@@ -554,7 +665,7 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
if (af_ops->ao_protinfo_policy) {
tb[IFLA_PROTINFO] = (struct nlattr *)af_ops->ao_protinfo_policy;
}
- link->l_family = family = af;
+ link->l_family = af;
link->l_af_ops = af_ops;
}
@@ -572,8 +683,19 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
/* XXX: Warn about unparsed info? */
}
}
+
+ link->ce_mask |= LINK_ATTR_LINKINFO;
+ }
+
+ if (li[IFLA_INFO_SLAVE_KIND]) {
+ const char *kind = nla_get_string(li[IFLA_INFO_SLAVE_KIND]);
+
+ err = rtnl_link_set_slave_type(link, kind);
+ if (err < 0)
+ goto errout;
+
+ link->ce_mask |= LINK_ATTR_LINKINFO_SLAVE_KIND;
}
- link->ce_mask |= LINK_ATTR_LINKINFO;
}
if (tb[IFLA_PROTINFO] && af_ops && af_ops->ao_parse_protinfo) {
@@ -585,21 +707,35 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
}
if (tb[IFLA_AF_SPEC]) {
- struct nlattr *af_attr;
- int remaining;
+ /* parsing of IFLA_AF_SPEC is dependent on the family used
+ * in the request message.
+ */
+ if (af_ops_family && af_ops_family->ao_parse_af_full) {
+ err = af_ops_family->ao_parse_af_full(link,
+ tb[IFLA_AF_SPEC],
+ link->l_af_data[af_ops_family->ao_family]);
+ if (err < 0)
+ goto errout;
+ link->ce_mask |= LINK_ATTR_AF_SPEC;
+ } else if (family == AF_UNSPEC) {
+ struct nlattr *af_attr;
+ int remaining;
- nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) {
- af_ops = af_lookup_and_alloc(link, nla_type(af_attr));
- if (af_ops && af_ops->ao_parse_af) {
- char *af_data = link->l_af_data[nla_type(af_attr)];
+ nla_for_each_nested(af_attr, tb[IFLA_AF_SPEC], remaining) {
+ af_ops = af_lookup_and_alloc(link, nla_type(af_attr));
+ if (af_ops && af_ops->ao_parse_af) {
+ char *af_data = link->l_af_data[nla_type(af_attr)];
- err = af_ops->ao_parse_af(link, af_attr, af_data);
- if (err < 0)
- goto errout;
+ err = af_ops->ao_parse_af(link, af_attr, af_data);
+ if (err < 0)
+ goto errout;
+ }
}
-
+ link->ce_mask |= LINK_ATTR_AF_SPEC;
+ } else {
+ NL_DBG(3, "IFLA_AF_SPEC parsing not implemented for family %d\n",
+ family);
}
- link->ce_mask |= LINK_ATTR_AF_SPEC;
}
if (tb[IFLA_PROMISCUITY]) {
@@ -617,6 +753,16 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
link->ce_mask |= LINK_ATTR_NUM_RX_QUEUES;
}
+ if (tb[IFLA_GSO_MAX_SEGS]) {
+ link->l_gso_max_segs = nla_get_u32(tb[IFLA_GSO_MAX_SEGS]);
+ link->ce_mask |= LINK_ATTR_GSO_MAX_SEGS;
+ }
+
+ if (tb[IFLA_GSO_MAX_SIZE]) {
+ link->l_gso_max_size = nla_get_u32(tb[IFLA_GSO_MAX_SIZE]);
+ link->ce_mask |= LINK_ATTR_GSO_MAX_SIZE;
+ }
+
if (tb[IFLA_GROUP]) {
link->l_group = nla_get_u32(tb[IFLA_GROUP]);
link->ce_mask |= LINK_ATTR_GROUP;
@@ -631,6 +777,20 @@ static int link_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
link->ce_mask |= LINK_ATTR_PHYS_PORT_ID;
}
+ if (tb[IFLA_PHYS_PORT_NAME]) {
+ nla_strlcpy(link->l_phys_port_name, tb[IFLA_PHYS_PORT_NAME], IFNAMSIZ);
+ link->ce_mask |= LINK_ATTR_PHYS_PORT_NAME;
+ }
+
+ if (tb[IFLA_PHYS_SWITCH_ID]) {
+ link->l_phys_switch_id = nl_data_alloc_attr(tb[IFLA_PHYS_SWITCH_ID]);
+ if (link->l_phys_switch_id == NULL) {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+ link->ce_mask |= LINK_ATTR_PHYS_SWITCH_ID;
+ }
+
err = pp->pp_cb((struct nl_object *) link, pp);
errout:
rtnl_link_af_ops_put(af_ops);
@@ -641,8 +801,40 @@ errout:
static int link_request_update(struct nl_cache *cache, struct nl_sock *sk)
{
int family = cache->c_iarg1;
+ struct ifinfomsg hdr = { .ifi_family = family };
+ struct rtnl_link_af_ops *ops;
+ struct nl_msg *msg;
+ int err;
+ __u32 ext_filter_mask = RTEXT_FILTER_VF;
+
+ msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_DUMP);
+ if (!msg)
+ return -NLE_NOMEM;
- return nl_rtgen_request(sk, RTM_GETLINK, family, NLM_F_DUMP);
+ err = -NLE_MSGSIZE;
+ if (nlmsg_append(msg, &hdr, sizeof(hdr), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ ops = rtnl_link_af_ops_lookup(family);
+ if (ops && ops->ao_get_af) {
+ err = ops->ao_get_af(msg, &ext_filter_mask);
+ if (err)
+ goto nla_put_failure;
+ }
+
+ if (ext_filter_mask) {
+ err = nla_put(msg, IFLA_EXT_MASK, sizeof(ext_filter_mask), &ext_filter_mask);
+ if (err)
+ goto nla_put_failure;
+ }
+
+ err = nl_send_auto(sk, msg);
+ if (err > 0)
+ err = 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return err;
}
static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
@@ -657,6 +849,9 @@ static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
fetched_cache = 1;
}
+ if (link->l_family != AF_UNSPEC)
+ nl_dump_line(p, "%s ", nl_af2str(link->l_family, buf, sizeof(buf)));
+
nl_dump_line(p, "%s %s ", link->l_name,
nl_llproto2str(link->l_arptype, buf, sizeof(buf)));
@@ -678,7 +873,8 @@ static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
nl_dump(p, "<%s> ", buf);
if (link->ce_mask & LINK_ATTR_LINK) {
- if (cache) {
+ if ( cache
+ && !(link->ce_mask & LINK_ATTR_LINK_NETNSID)) {
struct rtnl_link *ll = rtnl_link_get(cache, link->l_link);
nl_dump(p, "slave-of %s ", ll ? ll->l_name : "NONE");
if (ll)
@@ -686,6 +882,8 @@ static void link_dump_line(struct nl_object *obj, struct nl_dump_params *p)
} else
nl_dump(p, "slave-of %d ", link->l_link);
}
+ if (link->ce_mask & LINK_ATTR_LINK_NETNSID)
+ nl_dump(p, "link-netnsid %d ", link->l_link_netnsid);
if (link->ce_mask & LINK_ATTR_GROUP)
nl_dump(p, "group %u ", link->l_group);
@@ -755,12 +953,18 @@ static void link_dump_details(struct nl_object *obj, struct nl_dump_params *p)
nl_dump(p, "carrier %s",
rtnl_link_carrier2str(link->l_carrier, buf, sizeof(buf)));
+ if (link->ce_mask & LINK_ATTR_CARRIER_CHANGES)
+ nl_dump(p, " carrier-changes %u", link->l_carrier_changes);
+
nl_dump(p, "\n");
if (link->l_info_ops && link->l_info_ops->io_dump[NL_DUMP_DETAILS])
link->l_info_ops->io_dump[NL_DUMP_DETAILS](link, p);
do_foreach_af(link, af_dump_details, p);
+
+ if (link->ce_mask & LINK_ATTR_VF_LIST)
+ rtnl_link_sriov_dump_details(link, p);
}
static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
@@ -768,7 +972,7 @@ static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
struct rtnl_link *link = (struct rtnl_link *) obj;
char *unit, fmt[64];
float res;
-
+
link_dump_details(obj, p);
nl_dump_line(p, " Stats: bytes packets errors "
@@ -778,7 +982,7 @@ static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
strcpy(fmt, " RX %X.2f %s %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 "\n");
fmt[9] = *unit == 'B' ? '9' : '7';
-
+
nl_dump_line(p, fmt, res, unit,
link->l_stats[RTNL_LINK_RX_PACKETS],
link->l_stats[RTNL_LINK_RX_ERRORS],
@@ -790,7 +994,7 @@ static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
strcpy(fmt, " TX %X.2f %s %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 " %10" PRIu64 "\n");
fmt[9] = *unit == 'B' ? '9' : '7';
-
+
nl_dump_line(p, fmt, res, unit,
link->l_stats[RTNL_LINK_TX_PACKETS],
link->l_stats[RTNL_LINK_TX_ERRORS],
@@ -813,7 +1017,7 @@ static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
nl_dump_line(p, " aborted carrier heartbeat "
" window collision\n");
-
+
nl_dump_line(p, " TX %10" PRIu64 " %10" PRIu64 " %10"
PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
link->l_stats[RTNL_LINK_TX_ABORT_ERR],
@@ -826,6 +1030,9 @@ static void link_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
link->l_info_ops->io_dump[NL_DUMP_STATS](link, p);
do_foreach_af(link, af_dump_stats, p);
+
+ if (link->ce_mask & LINK_ATTR_VF_LIST)
+ rtnl_link_sriov_dump_stats(link, p);
}
#if 0
@@ -897,18 +1104,19 @@ static void link_keygen(struct nl_object *obj, uint32_t *hashkey,
return;
}
-static int link_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint64_t link_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct rtnl_link *a = (struct rtnl_link *) _a;
struct rtnl_link *b = (struct rtnl_link *) _b;
- int diff = 0;
+ uint64_t diff = 0;
#define LINK_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, LINK_ATTR_##ATTR, a, b, EXPR)
diff |= LINK_DIFF(IFINDEX, a->l_index != b->l_index);
diff |= LINK_DIFF(MTU, a->l_mtu != b->l_mtu);
diff |= LINK_DIFF(LINK, a->l_link != b->l_link);
+ diff |= LINK_DIFF(LINK_NETNSID, a->l_link_netnsid != b->l_link_netnsid);
diff |= LINK_DIFF(TXQLEN, a->l_txqlen != b->l_txqlen);
diff |= LINK_DIFF(WEIGHT, a->l_weight != b->l_weight);
diff |= LINK_DIFF(MASTER, a->l_master != b->l_master);
@@ -940,6 +1148,7 @@ static int link_compare(struct nl_object *_a, struct nl_object *_b,
goto protinfo_mismatch;
}
+ diff |= LINK_DIFF(LINKINFO, rtnl_link_info_data_compare(a, b, flags) != 0);
out:
return diff;
@@ -951,32 +1160,40 @@ protinfo_mismatch:
}
static const struct trans_tbl link_attrs[] = {
- __ADD(LINK_ATTR_MTU, mtu)
- __ADD(LINK_ATTR_LINK, link)
- __ADD(LINK_ATTR_TXQLEN, txqlen)
- __ADD(LINK_ATTR_WEIGHT, weight)
- __ADD(LINK_ATTR_MASTER, master)
- __ADD(LINK_ATTR_QDISC, qdisc)
- __ADD(LINK_ATTR_MAP, map)
- __ADD(LINK_ATTR_ADDR, address)
- __ADD(LINK_ATTR_BRD, broadcast)
- __ADD(LINK_ATTR_FLAGS, flags)
- __ADD(LINK_ATTR_IFNAME, name)
- __ADD(LINK_ATTR_IFINDEX, ifindex)
- __ADD(LINK_ATTR_FAMILY, family)
- __ADD(LINK_ATTR_ARPTYPE, arptype)
- __ADD(LINK_ATTR_STATS, stats)
- __ADD(LINK_ATTR_CHANGE, change)
- __ADD(LINK_ATTR_OPERSTATE, operstate)
- __ADD(LINK_ATTR_LINKMODE, linkmode)
- __ADD(LINK_ATTR_IFALIAS, ifalias)
- __ADD(LINK_ATTR_NUM_VF, num_vf)
- __ADD(LINK_ATTR_PROMISCUITY, promiscuity)
- __ADD(LINK_ATTR_NUM_TX_QUEUES, num_tx_queues)
- __ADD(LINK_ATTR_NUM_RX_QUEUES, num_rx_queues)
- __ADD(LINK_ATTR_GROUP, group)
- __ADD(LINK_ATTR_CARRIER, carrier)
- __ADD(LINK_ATTR_PHYS_PORT_ID, phys_port_id)
+ __ADD(LINK_ATTR_MTU, mtu),
+ __ADD(LINK_ATTR_LINK, link),
+ __ADD(LINK_ATTR_TXQLEN, txqlen),
+ __ADD(LINK_ATTR_WEIGHT, weight),
+ __ADD(LINK_ATTR_MASTER, master),
+ __ADD(LINK_ATTR_QDISC, qdisc),
+ __ADD(LINK_ATTR_MAP, map),
+ __ADD(LINK_ATTR_ADDR, address),
+ __ADD(LINK_ATTR_BRD, broadcast),
+ __ADD(LINK_ATTR_FLAGS, flags),
+ __ADD(LINK_ATTR_IFNAME, name),
+ __ADD(LINK_ATTR_IFINDEX, ifindex),
+ __ADD(LINK_ATTR_FAMILY, family),
+ __ADD(LINK_ATTR_ARPTYPE, arptype),
+ __ADD(LINK_ATTR_STATS, stats),
+ __ADD(LINK_ATTR_CHANGE, change),
+ __ADD(LINK_ATTR_OPERSTATE, operstate),
+ __ADD(LINK_ATTR_LINKMODE, linkmode),
+ __ADD(LINK_ATTR_IFALIAS, ifalias),
+ __ADD(LINK_ATTR_NUM_VF, num_vf),
+ __ADD(LINK_ATTR_PROMISCUITY, promiscuity),
+ __ADD(LINK_ATTR_NUM_TX_QUEUES, num_tx_queues),
+ __ADD(LINK_ATTR_NUM_RX_QUEUES, num_rx_queues),
+ __ADD(LINK_ATTR_GSO_MAX_SEGS, gso_max_segs),
+ __ADD(LINK_ATTR_GSO_MAX_SIZE, gso_max_size),
+ __ADD(LINK_ATTR_GROUP, group),
+ __ADD(LINK_ATTR_CARRIER, carrier),
+ __ADD(LINK_ATTR_CARRIER_CHANGES, carrier_changes),
+ __ADD(LINK_ATTR_PHYS_PORT_ID, phys_port_id),
+ __ADD(LINK_ATTR_PHYS_PORT_NAME, phys_port_name),
+ __ADD(LINK_ATTR_PHYS_SWITCH_ID, phys_switch_id),
+ __ADD(LINK_ATTR_NS_FD, ns_fd),
+ __ADD(LINK_ATTR_NS_PID, ns_pid),
+ __ADD(LINK_ATTR_LINK_NETNSID, link_netnsid),
};
static char *link_attrs2str(int attrs, char *buf, size_t len)
@@ -996,6 +1213,7 @@ static char *link_attrs2str(int attrs, char *buf, size_t len)
* @arg sk Netlink socket.
* @arg family Link address family or AF_UNSPEC
* @arg result Pointer to store resulting cache.
+ * @arg flags Flags to set in link cache before filling
*
* Allocates and initializes a new link cache. If \c sk is valid, a netlink
* message is sent to the kernel requesting a full dump of all configured
@@ -1015,17 +1233,21 @@ static char *link_attrs2str(int attrs, char *buf, size_t len)
* @see rtnl_link_get_by_name()
* @return 0 on success or a negative error code.
*/
-int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result)
+int rtnl_link_alloc_cache_flags(struct nl_sock *sk, int family,
+ struct nl_cache **result, unsigned int flags)
{
struct nl_cache * cache;
int err;
-
+
cache = nl_cache_alloc(&rtnl_link_ops);
if (!cache)
return -NLE_NOMEM;
cache->c_iarg1 = family;
-
+
+ if (flags)
+ nl_cache_set_flags(cache, flags);
+
if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
nl_cache_free(cache);
return err;
@@ -1036,6 +1258,36 @@ int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **resu
}
/**
+ * Allocate link cache and fill in all configured links.
+ * @arg sk Netlink socket.
+ * @arg family Link address family or AF_UNSPEC
+ * @arg result Pointer to store resulting cache.
+ *
+ * Allocates and initializes a new link cache. If \c sk is valid, a netlink
+ * message is sent to the kernel requesting a full dump of all configured
+ * links. The returned messages are parsed and filled into the cache. If
+ * the operation succeeds, the resulting cache will contain a link object for
+ * each link configured in the kernel. If \c sk is NULL, returns 0 but the
+ * cache is still empty.
+ *
+ * If \c family is set to an address family other than \c AF_UNSPEC the
+ * contents of the cache can be limited to a specific address family.
+ * Currently the following address families are supported:
+ * - AF_BRIDGE
+ * - AF_INET6
+ *
+ * @route_doc{link_list, Get List of Links}
+ * @see rtnl_link_get()
+ * @see rtnl_link_get_by_name()
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result)
+{
+ return rtnl_link_alloc_cache_flags(sk, family, result, 0);
+}
+
+
+/**
* Lookup link in cache by interface index
* @arg cache Link cache
* @arg ifindex Interface index
@@ -1119,6 +1371,8 @@ int rtnl_link_build_get_request(int ifindex, const char *name,
{
struct ifinfomsg ifi;
struct nl_msg *msg;
+ __u32 vf_mask = RTEXT_FILTER_VF;
+ int err = -NLE_MSGSIZE;
if (ifindex <= 0 && !name) {
APPBUG("ifindex or name must be specified");
@@ -1133,18 +1387,24 @@ int rtnl_link_build_get_request(int ifindex, const char *name,
if (ifindex > 0)
ifi.ifi_index = ifindex;
- if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
+ if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) {
+ err = -NLE_MSGSIZE;
goto nla_put_failure;
+ }
if (name)
NLA_PUT_STRING(msg, IFLA_IFNAME, name);
+ err = nla_put(msg, IFLA_EXT_MASK, sizeof(vf_mask), &vf_mask);
+ if (err)
+ goto nla_put_failure;
+
*result = msg;
return 0;
nla_put_failure:
nlmsg_free(msg);
- return -NLE_MSGSIZE;
+ return err;
}
/**
@@ -1160,6 +1420,11 @@ nla_put_failure:
* pointer or -NLE_OBJ_NOTFOUND is returned if no matching link was
* found.
*
+ * Older kernels do not support lookup by name. In that case, libnl
+ * will fail with -NLE_OPNOTSUPP. Note that previous version of libnl
+ * failed in this case with -NLE_INVAL. You can check libnl behavior
+ * using NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_FAIL_OPNOTSUPP capability.
+ *
* @route_doc{link_direct_lookup, Lookup Single Link (Direct Lookup)}
* @return 0 on success or a negative error code.
*/
@@ -1169,6 +1434,7 @@ int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
struct nl_msg *msg = NULL;
struct nl_object *obj;
int err;
+ int syserr;
if ((err = rtnl_link_build_get_request(ifindex, name, &msg)) < 0)
return err;
@@ -1178,15 +1444,25 @@ int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name,
if (err < 0)
return err;
- if ((err = nl_pickup(sk, link_msg_parser, &obj)) < 0)
+ if ((err = nl_pickup_keep_syserr(sk, link_msg_parser, &obj, &syserr)) < 0) {
+ if (syserr == -EINVAL &&
+ ifindex <= 0 &&
+ name && *name) {
+ /* Older kernels do not support lookup by ifname. This was added
+ * by commit kernel a3d1289126e7b14307074b76bf1677015ea5036f .
+ * Detect this error case and return NLE_OPNOTSUPP instead of
+ * NLE_INVAL. */
+ return -NLE_OPNOTSUPP;
+ }
return err;
+ }
/* We have used link_msg_parser(), object is definitely a link */
*result = (struct rtnl_link *) obj;
/* If an object has been returned, we also need to wait for the ACK */
- if (err == 0 && obj)
- wait_for_ack(sk);
+ if (err == 0 && obj)
+ wait_for_ack(sk);
return 0;
}
@@ -1232,7 +1508,7 @@ int rtnl_link_name2i(struct nl_cache *cache, const char *name)
{
int ifindex = 0;
struct rtnl_link *link;
-
+
link = rtnl_link_get_by_name(cache, name);
if (link) {
ifindex = link->l_index;
@@ -1279,6 +1555,9 @@ int rtnl_link_fill_info(struct nl_msg *msg, struct rtnl_link *link)
if (link->ce_mask & LINK_ATTR_LINK)
NLA_PUT_U32(msg, IFLA_LINK, link->l_link);
+ if (link->ce_mask & LINK_ATTR_LINK_NETNSID)
+ NLA_PUT_S32(msg, IFLA_LINK_NETNSID, link->l_link_netnsid);
+
if (link->ce_mask & LINK_ATTR_MASTER)
NLA_PUT_U32(msg, IFLA_MASTER, link->l_master);
@@ -1319,23 +1598,37 @@ static int build_link_msg(int cmd, struct ifinfomsg *hdr,
if (link->ce_mask & LINK_ATTR_GROUP)
NLA_PUT_U32(msg, IFLA_GROUP, link->l_group);
- if (link->ce_mask & LINK_ATTR_LINKINFO) {
+ if (link->ce_mask & (LINK_ATTR_LINKINFO|LINK_ATTR_LINKINFO_SLAVE_KIND)) {
struct nlattr *info;
if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
goto nla_put_failure;
- NLA_PUT_STRING(msg, IFLA_INFO_KIND, link->l_info_kind);
+ if (link->ce_mask & LINK_ATTR_LINKINFO) {
+ NLA_PUT_STRING(msg, IFLA_INFO_KIND, link->l_info_kind);
+
+ if (link->l_info_ops) {
+ if (link->l_info_ops->io_put_attrs &&
+ link->l_info_ops->io_put_attrs(msg, link) < 0)
+ goto nla_put_failure;
+ }
+ }
- if (link->l_info_ops) {
- if (link->l_info_ops->io_put_attrs &&
- link->l_info_ops->io_put_attrs(msg, link) < 0)
- goto nla_put_failure;
+ if (link->ce_mask & LINK_ATTR_LINKINFO_SLAVE_KIND) {
+ NLA_PUT_STRING(msg, IFLA_INFO_SLAVE_KIND, link->l_info_slave_kind);
}
nla_nest_end(msg, info);
}
+ if (link->ce_mask & LINK_ATTR_VF_LIST) {
+ if (rtnl_link_sriov_fill_vflist(msg, link) < 0)
+ goto nla_put_failure;
+ }
+
+ if (do_foreach_af(link, af_fill_pi, msg) < 0)
+ goto nla_put_failure;
+
if (!(af_spec = nla_nest_start(msg, IFLA_AF_SPEC)))
goto nla_put_failure;
@@ -1380,6 +1673,7 @@ int rtnl_link_build_add_request(struct rtnl_link *link, int flags,
.ifi_family = link->l_family,
.ifi_index = link->l_index,
.ifi_flags = link->l_flags,
+ .ifi_change = link->l_flag_mask,
};
return build_link_msg(RTM_NEWLINK, &ifi, link, flags, result);
@@ -1406,7 +1700,7 @@ int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags)
{
struct nl_msg *msg;
int err;
-
+
err = rtnl_link_build_add_request(link, flags, &msg);
if (err < 0)
return err;
@@ -1442,11 +1736,12 @@ int rtnl_link_build_change_request(struct rtnl_link *orig,
.ifi_family = orig->l_family,
.ifi_index = orig->l_index,
};
- int err;
+ int err, rt;
if (changes->ce_mask & LINK_ATTR_FLAGS) {
ifi.ifi_flags = orig->l_flags & ~changes->l_flag_mask;
ifi.ifi_flags |= changes->l_flags;
+ ifi.ifi_change = changes->l_flag_mask;
}
if (changes->l_family && changes->l_family != orig->l_family) {
@@ -1461,7 +1756,9 @@ int rtnl_link_build_change_request(struct rtnl_link *orig,
!strcmp(orig->l_name, changes->l_name))
changes->ce_mask &= ~LINK_ATTR_IFNAME;
- if ((err = build_link_msg(RTM_NEWLINK, &ifi, changes, flags, result)) < 0)
+ rt = af_request_type(orig->l_family, changes);
+
+ if ((err = build_link_msg(rt, &ifi, changes, flags, result)) < 0)
goto errout;
return 0;
@@ -1499,6 +1796,10 @@ errout:
* @note The link name can only be changed if the link has been put
* in opertional down state. (~IF_UP)
*
+ * @note On versions up to 3.4.0, \c NLE_SEQ_MISMATCH would be returned if the
+ * kernel does not supports \c RTM_NEWLINK. It is advised to ignore the
+ * error code if you cannot upgrade the library.
+ *
* @return 0 on success or a negative error code.
*/
int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *orig,
@@ -1506,11 +1807,12 @@ int rtnl_link_change(struct nl_sock *sk, struct rtnl_link *orig,
{
struct nl_msg *msg;
int err;
-
+
err = rtnl_link_build_change_request(orig, changes, flags, &msg);
if (err < 0)
return err;
+ BUG_ON(msg->nm_nlh->nlmsg_seq != NL_AUTO_SEQ);
retry:
err = nl_send_auto_complete(sk, msg);
if (err < 0)
@@ -1519,6 +1821,7 @@ retry:
err = wait_for_ack(sk);
if (err == -NLE_OPNOTSUPP && msg->nm_nlh->nlmsg_type == RTM_NEWLINK) {
msg->nm_nlh->nlmsg_type = RTM_SETLINK;
+ msg->nm_nlh->nlmsg_seq = NL_AUTO_SEQ;
goto retry;
}
@@ -1605,7 +1908,7 @@ int rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *link)
{
struct nl_msg *msg;
int err;
-
+
if ((err = rtnl_link_build_delete_request(link, &msg)) < 0)
return err;
@@ -1971,6 +2274,40 @@ int rtnl_link_get_link(struct rtnl_link *link)
}
/**
+ * Set the netnsid of the link
+ * @arg link Link object
+ * @link_netnsid the netnsid to set
+ *
+ * Sets the IFLA_LINK_NETNSID attribute of the link
+ * @returns 0 on success
+ */
+int rtnl_link_set_link_netnsid(struct rtnl_link *link, int32_t link_netnsid)
+{
+ link->l_link_netnsid = link_netnsid;
+ link->ce_mask |= LINK_ATTR_LINK_NETNSID;
+ return 0;
+}
+
+/**
+ * Get the netnsid of the link
+ * @arg link Link object
+ * @out_link_netnsid the netnsid
+ *
+ * Gets the IFLA_LINK_NETNSID attribute of the link
+ * or returns an error if the value is unset.
+ *
+ * @returns 0 on success
+ */
+int rtnl_link_get_link_netnsid(const struct rtnl_link *link, int32_t *out_link_netnsid)
+{
+ if (!(link->ce_mask & LINK_ATTR_LINK_NETNSID))
+ return -NLE_INVAL;
+
+ *out_link_netnsid = link->l_link_netnsid;
+ return 0;
+}
+
+/**
* Set master link of link object
* @arg link Link object
* @arg ifindex Interface index of master link
@@ -2021,6 +2358,24 @@ uint8_t rtnl_link_get_carrier(struct rtnl_link *link)
}
/**
+ * Return carrier on/off changes of link object
+ * @arg link Link object
+ * @arg carrier_changes Pointer to store number of carrier changes
+ *
+ * @return 0 on success, negative error number otherwise
+ */
+int rtnl_link_get_carrier_changes(struct rtnl_link *link, uint32_t *carrier_changes)
+{
+ if (!(link->ce_mask & LINK_ATTR_CARRIER_CHANGES))
+ return -NLE_NOATTR;
+
+ if (carrier_changes)
+ *carrier_changes = link->l_carrier_changes;
+
+ return 0;
+}
+
+/**
* Set operational status of link object
* @arg link Link object
* @arg status New opertional status
@@ -2208,7 +2563,7 @@ int rtnl_link_set_stat(struct rtnl_link *link, rtnl_link_stat_id_t id,
* be released with all link type specific attributes lost.
*
* @route_doc{link_modules, Link Modules}
- * @return 0 on success or a negative errror code.
+ * @return 0 on success or a negative error code.
*/
int rtnl_link_set_type(struct rtnl_link *link, const char *type)
{
@@ -2218,8 +2573,7 @@ int rtnl_link_set_type(struct rtnl_link *link, const char *type)
free(link->l_info_kind);
link->ce_mask &= ~LINK_ATTR_LINKINFO;
- if (link->l_info_ops)
- release_link_info(link);
+ release_link_info(link);
if (!type)
return 0;
@@ -2259,6 +2613,49 @@ char *rtnl_link_get_type(struct rtnl_link *link)
}
/**
+ * Set type of slave link object
+ * @arg link Link object (slave)
+ * @arg type Name of link type
+ *
+ * If a slave type has been assigned already it will be released.
+ *
+ * @route_doc{link_modules, Link Modules}
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_set_slave_type(struct rtnl_link *link, const char *type)
+{
+ char *kind = NULL;
+
+ if (type) {
+ kind = strdup(type);
+ if (!kind)
+ return -NLE_NOMEM;
+ }
+
+ free(link->l_info_slave_kind);
+ link->l_info_slave_kind = kind;
+
+ if (kind)
+ link->ce_mask |= LINK_ATTR_LINKINFO_SLAVE_KIND;
+ else
+ link->ce_mask &= ~LINK_ATTR_LINKINFO_SLAVE_KIND;
+ return 0;
+}
+
+/**
+ * Return type of enslaved link
+ * @arg link Link object
+ *
+ * @route_doc{link_modules, Link Modules}
+ * @return Name of enslaved link type or NULL if not specified.
+ */
+const char *rtnl_link_get_slave_type(const struct rtnl_link *link)
+{
+ return link->l_info_slave_kind;
+}
+
+
+/**
* Set link promiscuity count
* @arg link Link object
* @arg count New promiscuity count
@@ -2348,6 +2745,42 @@ uint32_t rtnl_link_get_num_rx_queues(struct rtnl_link *link)
}
/**
+ * Return maximum number of segments for generic segmentation offload
+ * @arg link Link object
+ * @arg gso_max_segs Pointer to store maximum number GSO segments
+ *
+ * @return 0 on success, negative error number otherwise
+ */
+int rtnl_link_get_gso_max_segs(struct rtnl_link *link, uint32_t *gso_max_segs)
+{
+ if (!(link->ce_mask & LINK_ATTR_GSO_MAX_SEGS))
+ return -NLE_NOATTR;
+
+ if (gso_max_segs)
+ *gso_max_segs = link->l_gso_max_segs;
+
+ return 0;
+}
+
+/**
+ * Return maximum size for generic segmentation offload
+ * @arg link Link object
+ * @arg gso_max_segs Pointer to store maximum GSO size
+ *
+ * @return 0 on success, negative error number otherwise
+ */
+int rtnl_link_get_gso_max_size(struct rtnl_link *link, uint32_t *gso_max_size)
+{
+ if (!(link->ce_mask & LINK_ATTR_GSO_MAX_SIZE))
+ return -NLE_NOATTR;
+
+ if (gso_max_size)
+ *gso_max_size = link->l_gso_max_size;
+
+ return 0;
+}
+
+/**
* Return physical port id of link object
* @arg link Link object
*
@@ -2358,6 +2791,28 @@ struct nl_data *rtnl_link_get_phys_port_id(struct rtnl_link *link)
return link->l_phys_port_id;
}
+/**
+ * Return physical port name of link object
+ * @arg link Link object
+ *
+ * @return Physical port name or NULL if not set.
+ */
+char *rtnl_link_get_phys_port_name(struct rtnl_link *link)
+{
+ return link->l_phys_port_name;
+}
+
+/*
+ * Return physical switch id of link object
+ * @arg link Link object
+ *
+ * @return Physical switch id or NULL if not set.
+ */
+struct nl_data *rtnl_link_get_phys_switch_id(struct rtnl_link *link)
+{
+ return link->l_phys_switch_id;
+}
+
void rtnl_link_set_ns_fd(struct rtnl_link *link, int fd)
{
link->l_ns_fd = fd;
@@ -2410,7 +2865,7 @@ int rtnl_link_enslave_ifindex(struct nl_sock *sock, int master, int slave)
rtnl_link_set_ifindex(link, slave);
rtnl_link_set_master(link, master);
-
+
if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
goto errout;
@@ -2511,25 +2966,25 @@ int rtnl_link_release(struct nl_sock *sock, struct rtnl_link *slave)
*/
static const struct trans_tbl link_flags[] = {
- __ADD(IFF_LOOPBACK, loopback)
- __ADD(IFF_BROADCAST, broadcast)
- __ADD(IFF_POINTOPOINT, pointopoint)
- __ADD(IFF_MULTICAST, multicast)
- __ADD(IFF_NOARP, noarp)
- __ADD(IFF_ALLMULTI, allmulti)
- __ADD(IFF_PROMISC, promisc)
- __ADD(IFF_MASTER, master)
- __ADD(IFF_SLAVE, slave)
- __ADD(IFF_DEBUG, debug)
- __ADD(IFF_DYNAMIC, dynamic)
- __ADD(IFF_AUTOMEDIA, automedia)
- __ADD(IFF_PORTSEL, portsel)
- __ADD(IFF_NOTRAILERS, notrailers)
- __ADD(IFF_UP, up)
- __ADD(IFF_RUNNING, running)
- __ADD(IFF_LOWER_UP, lowerup)
- __ADD(IFF_DORMANT, dormant)
- __ADD(IFF_ECHO, echo)
+ __ADD(IFF_LOOPBACK, loopback),
+ __ADD(IFF_BROADCAST, broadcast),
+ __ADD(IFF_POINTOPOINT, pointopoint),
+ __ADD(IFF_MULTICAST, multicast),
+ __ADD(IFF_NOARP, noarp),
+ __ADD(IFF_ALLMULTI, allmulti),
+ __ADD(IFF_PROMISC, promisc),
+ __ADD(IFF_MASTER, master),
+ __ADD(IFF_SLAVE, slave),
+ __ADD(IFF_DEBUG, debug),
+ __ADD(IFF_DYNAMIC, dynamic),
+ __ADD(IFF_AUTOMEDIA, automedia),
+ __ADD(IFF_PORTSEL, portsel),
+ __ADD(IFF_NOTRAILERS, notrailers),
+ __ADD(IFF_UP, up),
+ __ADD(IFF_RUNNING, running),
+ __ADD(IFF_LOWER_UP, lowerup),
+ __ADD(IFF_DORMANT, dormant),
+ __ADD(IFF_ECHO, echo),
};
char *rtnl_link_flags2str(int flags, char *buf, size_t len)
@@ -2544,69 +2999,70 @@ int rtnl_link_str2flags(const char *name)
}
static const struct trans_tbl link_stats[] = {
- __ADD(RTNL_LINK_RX_PACKETS, rx_packets)
- __ADD(RTNL_LINK_TX_PACKETS, tx_packets)
- __ADD(RTNL_LINK_RX_BYTES, rx_bytes)
- __ADD(RTNL_LINK_TX_BYTES, tx_bytes)
- __ADD(RTNL_LINK_RX_ERRORS, rx_errors)
- __ADD(RTNL_LINK_TX_ERRORS, tx_errors)
- __ADD(RTNL_LINK_RX_DROPPED, rx_dropped)
- __ADD(RTNL_LINK_TX_DROPPED, tx_dropped)
- __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed)
- __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed)
- __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err)
- __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err)
- __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err)
- __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err)
- __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err)
- __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err)
- __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err)
- __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err)
- __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err)
- __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err)
- __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err)
- __ADD(RTNL_LINK_COLLISIONS, collisions)
- __ADD(RTNL_LINK_MULTICAST, multicast)
- __ADD(RTNL_LINK_IP6_INPKTS, Ip6InReceives)
- __ADD(RTNL_LINK_IP6_INHDRERRORS, Ip6InHdrErrors)
- __ADD(RTNL_LINK_IP6_INTOOBIGERRORS, Ip6InTooBigErrors)
- __ADD(RTNL_LINK_IP6_INNOROUTES, Ip6InNoRoutes)
- __ADD(RTNL_LINK_IP6_INADDRERRORS, Ip6InAddrErrors)
- __ADD(RTNL_LINK_IP6_INUNKNOWNPROTOS, Ip6InUnknownProtos)
- __ADD(RTNL_LINK_IP6_INTRUNCATEDPKTS, Ip6InTruncatedPkts)
- __ADD(RTNL_LINK_IP6_INDISCARDS, Ip6InDiscards)
- __ADD(RTNL_LINK_IP6_INDELIVERS, Ip6InDelivers)
- __ADD(RTNL_LINK_IP6_OUTFORWDATAGRAMS, Ip6OutForwDatagrams)
- __ADD(RTNL_LINK_IP6_OUTPKTS, Ip6OutRequests)
- __ADD(RTNL_LINK_IP6_OUTDISCARDS, Ip6OutDiscards)
- __ADD(RTNL_LINK_IP6_OUTNOROUTES, Ip6OutNoRoutes)
- __ADD(RTNL_LINK_IP6_REASMTIMEOUT, Ip6ReasmTimeout)
- __ADD(RTNL_LINK_IP6_REASMREQDS, Ip6ReasmReqds)
- __ADD(RTNL_LINK_IP6_REASMOKS, Ip6ReasmOKs)
- __ADD(RTNL_LINK_IP6_REASMFAILS, Ip6ReasmFails)
- __ADD(RTNL_LINK_IP6_FRAGOKS, Ip6FragOKs)
- __ADD(RTNL_LINK_IP6_FRAGFAILS, Ip6FragFails)
- __ADD(RTNL_LINK_IP6_FRAGCREATES, Ip6FragCreates)
- __ADD(RTNL_LINK_IP6_INMCASTPKTS, Ip6InMcastPkts)
- __ADD(RTNL_LINK_IP6_OUTMCASTPKTS, Ip6OutMcastPkts)
- __ADD(RTNL_LINK_IP6_INBCASTPKTS, Ip6InBcastPkts)
- __ADD(RTNL_LINK_IP6_OUTBCASTPKTS, Ip6OutBcastPkts)
- __ADD(RTNL_LINK_IP6_INOCTETS, Ip6InOctets)
- __ADD(RTNL_LINK_IP6_OUTOCTETS, Ip6OutOctets)
- __ADD(RTNL_LINK_IP6_INMCASTOCTETS, Ip6InMcastOctets)
- __ADD(RTNL_LINK_IP6_OUTMCASTOCTETS, Ip6OutMcastOctets)
- __ADD(RTNL_LINK_IP6_INBCASTOCTETS, Ip6InBcastOctets)
- __ADD(RTNL_LINK_IP6_OUTBCASTOCTETS, Ip6OutBcastOctets)
- __ADD(RTNL_LINK_ICMP6_INMSGS, ICMP6_InMsgs)
- __ADD(RTNL_LINK_ICMP6_INERRORS, ICMP6_InErrors)
- __ADD(RTNL_LINK_ICMP6_OUTMSGS, ICMP6_OutMsgs)
- __ADD(RTNL_LINK_ICMP6_OUTERRORS, ICMP6_OutErrors)
- __ADD(RTNL_LINK_ICMP6_CSUMERRORS, ICMP6_InCsumErrors)
- __ADD(RTNL_LINK_IP6_CSUMERRORS, Ip6_InCsumErrors)
- __ADD(RTNL_LINK_IP6_NOECTPKTS, Ip6_InNoECTPkts)
- __ADD(RTNL_LINK_IP6_ECT1PKTS, Ip6_InECT1Pkts)
- __ADD(RTNL_LINK_IP6_ECT0PKTS, Ip6_InECT0Pkts)
- __ADD(RTNL_LINK_IP6_CEPKTS, Ip6_InCEPkts)
+ __ADD(RTNL_LINK_RX_PACKETS, rx_packets),
+ __ADD(RTNL_LINK_TX_PACKETS, tx_packets),
+ __ADD(RTNL_LINK_RX_BYTES, rx_bytes),
+ __ADD(RTNL_LINK_TX_BYTES, tx_bytes),
+ __ADD(RTNL_LINK_RX_ERRORS, rx_errors),
+ __ADD(RTNL_LINK_TX_ERRORS, tx_errors),
+ __ADD(RTNL_LINK_RX_DROPPED, rx_dropped),
+ __ADD(RTNL_LINK_TX_DROPPED, tx_dropped),
+ __ADD(RTNL_LINK_RX_COMPRESSED, rx_compressed),
+ __ADD(RTNL_LINK_TX_COMPRESSED, tx_compressed),
+ __ADD(RTNL_LINK_RX_FIFO_ERR, rx_fifo_err),
+ __ADD(RTNL_LINK_TX_FIFO_ERR, tx_fifo_err),
+ __ADD(RTNL_LINK_RX_LEN_ERR, rx_len_err),
+ __ADD(RTNL_LINK_RX_OVER_ERR, rx_over_err),
+ __ADD(RTNL_LINK_RX_CRC_ERR, rx_crc_err),
+ __ADD(RTNL_LINK_RX_FRAME_ERR, rx_frame_err),
+ __ADD(RTNL_LINK_RX_MISSED_ERR, rx_missed_err),
+ __ADD(RTNL_LINK_TX_ABORT_ERR, tx_abort_err),
+ __ADD(RTNL_LINK_TX_CARRIER_ERR, tx_carrier_err),
+ __ADD(RTNL_LINK_TX_HBEAT_ERR, tx_hbeat_err),
+ __ADD(RTNL_LINK_TX_WIN_ERR, tx_win_err),
+ __ADD(RTNL_LINK_COLLISIONS, collisions),
+ __ADD(RTNL_LINK_MULTICAST, multicast),
+ __ADD(RTNL_LINK_IP6_INPKTS, Ip6InReceives),
+ __ADD(RTNL_LINK_IP6_INHDRERRORS, Ip6InHdrErrors),
+ __ADD(RTNL_LINK_IP6_INTOOBIGERRORS, Ip6InTooBigErrors),
+ __ADD(RTNL_LINK_IP6_INNOROUTES, Ip6InNoRoutes),
+ __ADD(RTNL_LINK_IP6_INADDRERRORS, Ip6InAddrErrors),
+ __ADD(RTNL_LINK_IP6_INUNKNOWNPROTOS, Ip6InUnknownProtos),
+ __ADD(RTNL_LINK_IP6_INTRUNCATEDPKTS, Ip6InTruncatedPkts),
+ __ADD(RTNL_LINK_IP6_INDISCARDS, Ip6InDiscards),
+ __ADD(RTNL_LINK_IP6_INDELIVERS, Ip6InDelivers),
+ __ADD(RTNL_LINK_IP6_OUTFORWDATAGRAMS, Ip6OutForwDatagrams),
+ __ADD(RTNL_LINK_IP6_OUTPKTS, Ip6OutRequests),
+ __ADD(RTNL_LINK_IP6_OUTDISCARDS, Ip6OutDiscards),
+ __ADD(RTNL_LINK_IP6_OUTNOROUTES, Ip6OutNoRoutes),
+ __ADD(RTNL_LINK_IP6_REASMTIMEOUT, Ip6ReasmTimeout),
+ __ADD(RTNL_LINK_IP6_REASMREQDS, Ip6ReasmReqds),
+ __ADD(RTNL_LINK_IP6_REASMOKS, Ip6ReasmOKs),
+ __ADD(RTNL_LINK_IP6_REASMFAILS, Ip6ReasmFails),
+ __ADD(RTNL_LINK_IP6_FRAGOKS, Ip6FragOKs),
+ __ADD(RTNL_LINK_IP6_FRAGFAILS, Ip6FragFails),
+ __ADD(RTNL_LINK_IP6_FRAGCREATES, Ip6FragCreates),
+ __ADD(RTNL_LINK_IP6_INMCASTPKTS, Ip6InMcastPkts),
+ __ADD(RTNL_LINK_IP6_OUTMCASTPKTS, Ip6OutMcastPkts),
+ __ADD(RTNL_LINK_IP6_INBCASTPKTS, Ip6InBcastPkts),
+ __ADD(RTNL_LINK_IP6_OUTBCASTPKTS, Ip6OutBcastPkts),
+ __ADD(RTNL_LINK_IP6_INOCTETS, Ip6InOctets),
+ __ADD(RTNL_LINK_IP6_OUTOCTETS, Ip6OutOctets),
+ __ADD(RTNL_LINK_IP6_INMCASTOCTETS, Ip6InMcastOctets),
+ __ADD(RTNL_LINK_IP6_OUTMCASTOCTETS, Ip6OutMcastOctets),
+ __ADD(RTNL_LINK_IP6_INBCASTOCTETS, Ip6InBcastOctets),
+ __ADD(RTNL_LINK_IP6_OUTBCASTOCTETS, Ip6OutBcastOctets),
+ __ADD(RTNL_LINK_ICMP6_INMSGS, ICMP6_InMsgs),
+ __ADD(RTNL_LINK_ICMP6_INERRORS, ICMP6_InErrors),
+ __ADD(RTNL_LINK_ICMP6_OUTMSGS, ICMP6_OutMsgs),
+ __ADD(RTNL_LINK_ICMP6_OUTERRORS, ICMP6_OutErrors),
+ __ADD(RTNL_LINK_ICMP6_CSUMERRORS, ICMP6_InCsumErrors),
+ __ADD(RTNL_LINK_IP6_CSUMERRORS, Ip6_InCsumErrors),
+ __ADD(RTNL_LINK_IP6_NOECTPKTS, Ip6_InNoECTPkts),
+ __ADD(RTNL_LINK_IP6_ECT1PKTS, Ip6_InECT1Pkts),
+ __ADD(RTNL_LINK_IP6_ECT0PKTS, Ip6_InECT0Pkts),
+ __ADD(RTNL_LINK_IP6_CEPKTS, Ip6_InCEPkts),
+ __ADD(RTNL_LINK_RX_NOHANDLER, rx_nohandler),
};
char *rtnl_link_stat2str(int st, char *buf, size_t len)
@@ -2620,13 +3076,13 @@ int rtnl_link_str2stat(const char *name)
}
static const struct trans_tbl link_operstates[] = {
- __ADD(IF_OPER_UNKNOWN, unknown)
- __ADD(IF_OPER_NOTPRESENT, notpresent)
- __ADD(IF_OPER_DOWN, down)
- __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown)
- __ADD(IF_OPER_TESTING, testing)
- __ADD(IF_OPER_DORMANT, dormant)
- __ADD(IF_OPER_UP, up)
+ __ADD(IF_OPER_UNKNOWN, unknown),
+ __ADD(IF_OPER_NOTPRESENT, notpresent),
+ __ADD(IF_OPER_DOWN, down),
+ __ADD(IF_OPER_LOWERLAYERDOWN, lowerlayerdown),
+ __ADD(IF_OPER_TESTING, testing),
+ __ADD(IF_OPER_DORMANT, dormant),
+ __ADD(IF_OPER_UP, up),
};
char *rtnl_link_operstate2str(uint8_t st, char *buf, size_t len)
@@ -2642,13 +3098,13 @@ int rtnl_link_str2operstate(const char *name)
}
static const struct trans_tbl link_modes[] = {
- __ADD(IF_LINK_MODE_DEFAULT, default)
- __ADD(IF_LINK_MODE_DORMANT, dormant)
+ __ADD(IF_LINK_MODE_DEFAULT, default),
+ __ADD(IF_LINK_MODE_DORMANT, dormant),
};
static const struct trans_tbl carrier_states[] = {
- __ADD(IF_CARRIER_DOWN, down)
- __ADD(IF_CARRIER_UP, up)
+ __ADD(0, down),
+ __ADD(1, up),
};
char *rtnl_link_mode2str(uint8_t st, char *buf, size_t len)
@@ -2672,6 +3128,31 @@ int rtnl_link_str2carrier(const char *name)
return __str2type(name, carrier_states, ARRAY_SIZE(carrier_states));
}
+int rtnl_link_has_vf_list(struct rtnl_link *link) {
+ if (link->ce_mask & LINK_ATTR_VF_LIST)
+ return 1;
+ else
+ return 0;
+}
+
+void rtnl_link_set_vf_list(struct rtnl_link *link) {
+ int err;
+
+ if (!(err = rtnl_link_has_vf_list(link)))
+ link->ce_mask |= LINK_ATTR_VF_LIST;
+
+ return;
+}
+
+void rtnl_link_unset_vf_list(struct rtnl_link *link) {
+ int err;
+
+ if ((err = rtnl_link_has_vf_list(link)))
+ link->ce_mask &= ~LINK_ATTR_VF_LIST;
+
+ return;
+}
+
/** @} */
/**
diff --git a/lib/route/link/api.c b/lib/route/link/api.c
index 6d1e12f8..d406783e 100644
--- a/lib/route/link/api.c
+++ b/lib/route/link/api.c
@@ -391,6 +391,28 @@ out:
return ret;
}
+/**
+ * Compare link info data
+ * @arg a Link object a
+ * @arg b Link object b
+ *
+ * This function will compare link_info data between two links
+ * a and b
+ *
+ * @return 0 if link_info data matches or is not present
+ * or != 0 if it mismatches.
+ */
+int rtnl_link_info_data_compare(struct rtnl_link *a, struct rtnl_link *b, int flags)
+{
+ if (a->l_info_ops != b->l_info_ops)
+ return ~0;
+
+ if (!a->l_info_ops || !a->l_info_ops->io_compare)
+ return 0;
+
+ return a->l_info_ops->io_compare(a, b, flags);
+}
+
/** @} */
/** @} */
diff --git a/lib/route/link/bonding.c b/lib/route/link/bonding.c
index f4c520bc..11b6d3d1 100644
--- a/lib/route/link/bonding.c
+++ b/lib/route/link/bonding.c
@@ -22,6 +22,7 @@
#include <netlink-private/netlink.h>
#include <netlink/netlink.h>
+#include <netlink/route/link/bonding.h>
#include <netlink-private/route/link/api.h>
/**
diff --git a/lib/route/link/bridge.c b/lib/route/link/bridge.c
index 4ca5f6e6..2d95faf8 100644
--- a/lib/route/link/bridge.c
+++ b/lib/route/link/bridge.c
@@ -25,11 +25,16 @@
#include <netlink-private/route/link/api.h>
#include <linux/if_bridge.h>
+#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */
+
/** @cond SKIP */
#define BRIDGE_ATTR_PORT_STATE (1 << 0)
#define BRIDGE_ATTR_PRIORITY (1 << 1)
#define BRIDGE_ATTR_COST (1 << 2)
#define BRIDGE_ATTR_FLAGS (1 << 3)
+#define BRIDGE_ATTR_PORT_VLAN (1 << 4)
+#define BRIDGE_ATTR_HWMODE (1 << 5)
+#define BRIDGE_ATTR_SELF (1 << 6)
#define PRIV_FLAG_NEW_ATTRS (1 << 0)
@@ -37,13 +42,38 @@ struct bridge_data
{
uint8_t b_port_state;
uint8_t b_priv_flags; /* internal flags */
+ uint16_t b_hwmode;
uint16_t b_priority;
+ uint16_t b_self; /* here for comparison reasons */
uint32_t b_cost;
uint32_t b_flags;
uint32_t b_flags_mask;
uint32_t ce_mask; /* HACK to support attr macros */
+ struct rtnl_link_bridge_vlan vlan_info;
};
+static void set_bit(unsigned nr, uint32_t *addr)
+{
+ if (nr < RTNL_LINK_BRIDGE_VLAN_BITMAP_MAX)
+ addr[nr / 32] |= (((uint32_t) 1) << (nr % 32));
+}
+
+static int find_next_bit(int i, uint32_t x)
+{
+ int j;
+
+ if (i >= 32)
+ return -1;
+
+ /* find first bit */
+ if (i < 0)
+ return __builtin_ffs(x);
+
+ /* mask off prior finds to get next */
+ j = __builtin_ffs(x >> i);
+ return j ? j + i : 0;
+}
+
static struct rtnl_link_af_ops bridge_ops;
#define IS_BRIDGE_LINK_ASSERT(link) \
@@ -85,6 +115,9 @@ static struct nla_policy br_attrs_policy[IFLA_BRPORT_MAX+1] = {
[IFLA_BRPORT_GUARD] = { .type = NLA_U8 },
[IFLA_BRPORT_PROTECT] = { .type = NLA_U8 },
[IFLA_BRPORT_FAST_LEAVE] = { .type = NLA_U8 },
+ [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 },
+ [IFLA_BRPORT_LEARNING_SYNC] = { .type = NLA_U8 },
+ [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
};
static void check_flag(struct rtnl_link *link, struct nlattr *attrs[],
@@ -137,10 +170,228 @@ static int bridge_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
check_flag(link, br_attrs, IFLA_BRPORT_GUARD, RTNL_BRIDGE_BPDU_GUARD);
check_flag(link, br_attrs, IFLA_BRPORT_PROTECT, RTNL_BRIDGE_ROOT_BLOCK);
check_flag(link, br_attrs, IFLA_BRPORT_FAST_LEAVE, RTNL_BRIDGE_FAST_LEAVE);
+ check_flag(link, br_attrs, IFLA_BRPORT_UNICAST_FLOOD,
+ RTNL_BRIDGE_UNICAST_FLOOD);
+ check_flag(link, br_attrs, IFLA_BRPORT_LEARNING, RTNL_BRIDGE_LEARNING);
+ check_flag(link, br_attrs, IFLA_BRPORT_LEARNING_SYNC,
+ RTNL_BRIDGE_LEARNING_SYNC);
+
+ return 0;
+}
+
+static int bridge_parse_af_full(struct rtnl_link *link, struct nlattr *attr_full,
+ void *data)
+{
+ struct bridge_data *bd = data;
+ struct bridge_vlan_info *vinfo = NULL;
+ uint16_t vid_range_start = 0;
+ uint16_t vid_range_flags = -1;
+
+ struct nlattr *attr;
+ int remaining;
+
+ nla_for_each_nested(attr, attr_full, remaining) {
+
+ if (nla_type(attr) == IFLA_BRIDGE_MODE) {
+ bd->b_hwmode = nla_get_u16(attr);
+ bd->ce_mask |= BRIDGE_ATTR_HWMODE;
+ } else if (nla_type(attr) != IFLA_BRIDGE_VLAN_INFO)
+ continue;
+
+ if (nla_len(attr) != sizeof(struct bridge_vlan_info))
+ return -EINVAL;
+
+ vinfo = nla_data(attr);
+ if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK)
+ return -EINVAL;
+
+
+ if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
+ vid_range_start = vinfo->vid;
+ vid_range_flags = (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_BEGIN);
+ continue;
+ }
+
+ if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END) {
+ /* sanity check the range flags */
+ if (vid_range_flags != (vinfo->flags ^ BRIDGE_VLAN_INFO_RANGE_END)) {
+ NL_DBG(1, "VLAN range flags differ; can not handle it.\n");
+ return -EINVAL;
+ }
+ } else {
+ vid_range_start = vinfo->vid;
+ }
+
+ for (; vid_range_start <= vinfo->vid; vid_range_start++) {
+ if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
+ bd->vlan_info.pvid = vinfo->vid;
+
+ if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
+ set_bit(vid_range_start, bd->vlan_info.untagged_bitmap);
+
+ set_bit(vid_range_start, bd->vlan_info.vlan_bitmap);
+ bd->ce_mask |= BRIDGE_ATTR_PORT_VLAN;
+ }
+
+ vid_range_flags = -1;
+ }
return 0;
}
+static int bridge_fill_af(struct rtnl_link *link, struct nl_msg *msg,
+ void *data)
+{
+ struct bridge_data *bd = data;
+
+ if ((bd->ce_mask & BRIDGE_ATTR_SELF)||(bd->ce_mask & BRIDGE_ATTR_HWMODE))
+ NLA_PUT_U16(msg, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF);
+
+ if (bd->ce_mask & BRIDGE_ATTR_HWMODE)
+ NLA_PUT_U16(msg, IFLA_BRIDGE_MODE, bd->b_hwmode);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+static int bridge_fill_pi(struct rtnl_link *link, struct nl_msg *msg,
+ void *data)
+{
+ struct bridge_data *bd = data;
+
+ if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
+ if (bd->b_flags_mask & RTNL_BRIDGE_BPDU_GUARD) {
+ NLA_PUT_U8(msg, IFLA_BRPORT_GUARD,
+ bd->b_flags & RTNL_BRIDGE_BPDU_GUARD);
+ }
+ if (bd->b_flags_mask & RTNL_BRIDGE_HAIRPIN_MODE) {
+ NLA_PUT_U8(msg, IFLA_BRPORT_MODE,
+ bd->b_flags & RTNL_BRIDGE_HAIRPIN_MODE);
+ }
+ if (bd->b_flags_mask & RTNL_BRIDGE_FAST_LEAVE) {
+ NLA_PUT_U8(msg, IFLA_BRPORT_FAST_LEAVE,
+ bd->b_flags & RTNL_BRIDGE_FAST_LEAVE);
+ }
+ if (bd->b_flags_mask & RTNL_BRIDGE_ROOT_BLOCK) {
+ NLA_PUT_U8(msg, IFLA_BRPORT_PROTECT,
+ bd->b_flags & RTNL_BRIDGE_ROOT_BLOCK);
+ }
+ if (bd->b_flags_mask & RTNL_BRIDGE_UNICAST_FLOOD) {
+ NLA_PUT_U8(msg, IFLA_BRPORT_UNICAST_FLOOD,
+ bd->b_flags & RTNL_BRIDGE_UNICAST_FLOOD);
+ }
+ if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING) {
+ NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING,
+ bd->b_flags & RTNL_BRIDGE_LEARNING);
+ }
+ if (bd->b_flags_mask & RTNL_BRIDGE_LEARNING_SYNC) {
+ NLA_PUT_U8(msg, IFLA_BRPORT_LEARNING_SYNC,
+ bd->b_flags & RTNL_BRIDGE_LEARNING_SYNC);
+ }
+ }
+
+ if (bd->ce_mask & BRIDGE_ATTR_COST)
+ NLA_PUT_U32(msg, IFLA_BRPORT_COST, bd->b_cost);
+
+ if (bd->ce_mask & BRIDGE_ATTR_PRIORITY)
+ NLA_PUT_U16(msg, IFLA_BRPORT_PRIORITY, bd->b_priority);
+
+ if (bd->ce_mask & BRIDGE_ATTR_PORT_STATE)
+ NLA_PUT_U8(msg, IFLA_BRPORT_STATE, bd->b_port_state);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+static int bridge_override_rtm(struct rtnl_link *link) {
+ struct bridge_data *bd;
+
+ if (!rtnl_link_is_bridge(link))
+ return 0;
+
+ bd = bridge_data(link);
+
+ if (bd->ce_mask & BRIDGE_ATTR_FLAGS)
+ return 1;
+
+ return 0;
+}
+
+static int bridge_get_af(struct nl_msg *msg, uint32_t *ext_filter_mask)
+{
+ *ext_filter_mask |= RTEXT_FILTER_BRVLAN;
+ return 0;
+}
+
+static void dump_bitmap(struct nl_dump_params *p, const uint32_t *b)
+{
+ int i = -1, j, k;
+ int start = -1, prev = -1;
+ int done, found = 0;
+
+ for (k = 0; k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; k++) {
+ int base_bit;
+ uint32_t a = b[k];
+
+ base_bit = k * 32;
+ i = -1;
+ done = 0;
+ while (!done) {
+ j = find_next_bit(i, a);
+ if (j > 0) {
+ /* first hit of any bit */
+ if (start < 0 && prev < 0) {
+ start = prev = j - 1 + base_bit;
+ goto next;
+ }
+ /* this bit is a continuation of prior bits */
+ if (j - 2 + base_bit == prev) {
+ prev++;
+ goto next;
+ }
+ } else
+ done = 1;
+
+ if (start >= 0) {
+ found++;
+ if (done && k < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN - 1)
+ break;
+
+ nl_dump(p, " %d", start);
+ if (start != prev)
+ nl_dump(p, "-%d", prev);
+
+ if (done)
+ break;
+ }
+ if (j > 0)
+ start = prev = j - 1 + base_bit;
+next:
+ i = j;
+ }
+ }
+ if (!found)
+ nl_dump(p, " <none>");
+
+ return;
+}
+
+static void rtnl_link_bridge_dump_vlans(struct nl_dump_params *p,
+ struct bridge_data *bd)
+{
+ nl_dump(p, "pvid %u", bd->vlan_info.pvid);
+
+ nl_dump(p, " all vlans:");
+ dump_bitmap(p, bd->vlan_info.vlan_bitmap);
+
+ nl_dump(p, " untagged vlans:");
+ dump_bitmap(p, bd->vlan_info.untagged_bitmap);
+}
+
static void bridge_dump_details(struct rtnl_link *link,
struct nl_dump_params *p, void *data)
{
@@ -157,6 +408,24 @@ static void bridge_dump_details(struct rtnl_link *link,
if (bd->ce_mask & BRIDGE_ATTR_COST)
nl_dump(p, "cost %u ", bd->b_cost);
+ if (bd->ce_mask & BRIDGE_ATTR_HWMODE) {
+ char hbuf[32];
+
+ rtnl_link_bridge_hwmode2str(bd->b_hwmode, hbuf, sizeof(hbuf));
+ nl_dump(p, "hwmode %s", hbuf);
+ }
+
+ if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
+ rtnl_link_bridge_dump_vlans(p, bd);
+
+ if (bd->ce_mask & BRIDGE_ATTR_FLAGS) {
+ char buf[256];
+
+ rtnl_link_bridge_flags2str(bd->b_flags & bd->b_flags_mask,
+ buf, sizeof(buf));
+ nl_dump(p, "%s", buf);
+ }
+
nl_dump(p, "\n");
}
@@ -171,6 +440,10 @@ static int bridge_compare(struct rtnl_link *_a, struct rtnl_link *_b,
diff |= BRIDGE_DIFF(PORT_STATE, a->b_port_state != b->b_port_state);
diff |= BRIDGE_DIFF(PRIORITY, a->b_priority != b->b_priority);
diff |= BRIDGE_DIFF(COST, a->b_cost != b->b_cost);
+ diff |= BRIDGE_DIFF(PORT_VLAN, memcmp(&a->vlan_info, &b->vlan_info,
+ sizeof(struct rtnl_link_bridge_vlan)));
+ diff |= BRIDGE_DIFF(HWMODE, a->b_hwmode != b->b_hwmode);
+ diff |= BRIDGE_DIFF(SELF, a->b_self != b->b_self);
if (flags & LOOSE_COMPARISON)
diff |= BRIDGE_DIFF(FLAGS,
@@ -203,8 +476,8 @@ struct rtnl_link *rtnl_link_bridge_alloc(void)
return link;
}
-
-/**
+
+/**
* Create a new kernel bridge device
* @arg sk netlink socket
* @arg name name of the bridge device or NULL
@@ -440,6 +713,9 @@ int rtnl_link_bridge_unset_flags(struct rtnl_link *link, unsigned int flags)
* - RTNL_BRIDGE_BPDU_GUARD
* - RTNL_BRIDGE_ROOT_BLOCK
* - RTNL_BRIDGE_FAST_LEAVE
+ * - RTNL_BRIDGE_UNICAST_FLOOD
+ * - RTNL_BRIDGE_LEARNING
+ * - RTNL_BRIDGE_LEARNING_SYNC
*
* @see rtnl_link_bridge_unset_flags()
* @see rtnl_link_bridge_get_flags()
@@ -479,11 +755,99 @@ int rtnl_link_bridge_get_flags(struct rtnl_link *link)
return bd->b_flags;
}
+/**
+ * Set link change type to self
+ * @arg link Link Object of type bridge
+ *
+ * This will set the bridge change flag to self, meaning that changes to
+ * be applied with this link object will be applied directly to the physical
+ * device in a bridge instead of the virtual device.
+ *
+ * @return 0 on success or negative error code
+ * @return -NLE_OPNOTSUP Link is not a bridge
+ */
+int rtnl_link_bridge_set_self(struct rtnl_link *link)
+{
+ struct bridge_data *bd = bridge_data(link);
+
+ IS_BRIDGE_LINK_ASSERT(link);
+
+ bd->b_self |= 1;
+ bd->ce_mask |= BRIDGE_ATTR_SELF;
+
+ return 0;
+}
+
+/**
+ * Get hardware mode
+ * @arg link Link object of type bridge
+ * @arg hwmode Output argument.
+ *
+ * @see rtnl_link_bridge_set_hwmode()
+ *
+ * @return 0 if hardware mode is present and returned in hwmode
+ * @return -NLE_NOATTR if hardware mode is not present
+ * @return -NLE_OPNOTSUP Link is not a bridge
+ */
+int rtnl_link_bridge_get_hwmode(struct rtnl_link *link, uint16_t *hwmode)
+{
+ struct bridge_data *bd = bridge_data(link);
+
+ IS_BRIDGE_LINK_ASSERT(link);
+
+ if (!(bd->ce_mask & BRIDGE_ATTR_HWMODE))
+ return -NLE_NOATTR;
+
+ *hwmode = bd->b_hwmode;
+ return 0;
+}
+
+/**
+ * Set hardware mode
+ * @arg link Link object of type bridge
+ * @arg hwmode Hardware mode to set on link
+ *
+ * This will set the hardware mode of a link when it supports hardware
+ * offloads for bridging.
+ * @see rtnl_link_bridge_get_hwmode()
+ *
+ * Valid modes are:
+ * - RTNL_BRIDGE_HWMODE_VEB
+ * - RTNL_BRIDGE_HWMODE_VEPA
+ *
+ * When setting hardware mode, the change type will be set to self.
+ * @see rtnl_link_bridge_set_self()
+ *
+ * @return 0 on success or negative error code
+ * @return -NLE_OPNOTSUP Link is not a bridge
+ * @return -NLE_INVAL when specified hwmode is unsupported.
+ */
+int rtnl_link_bridge_set_hwmode(struct rtnl_link *link, uint16_t hwmode)
+{
+ int err;
+ struct bridge_data *bd = bridge_data(link);
+
+ if (hwmode > RTNL_BRIDGE_HWMODE_MAX)
+ return -NLE_INVAL;
+
+ if ((err = rtnl_link_bridge_set_self(link)) < 0)
+ return err;
+
+ bd->b_hwmode = hwmode;
+ bd->ce_mask |= BRIDGE_ATTR_HWMODE;
+
+ return 0;
+}
+
+
static const struct trans_tbl bridge_flags[] = {
- __ADD(RTNL_BRIDGE_HAIRPIN_MODE, hairpin_mode)
- __ADD(RTNL_BRIDGE_BPDU_GUARD, bpdu_guard)
- __ADD(RTNL_BRIDGE_ROOT_BLOCK, root_block)
- __ADD(RTNL_BRIDGE_FAST_LEAVE, fast_leave)
+ __ADD(RTNL_BRIDGE_HAIRPIN_MODE, hairpin_mode),
+ __ADD(RTNL_BRIDGE_BPDU_GUARD, bpdu_guard),
+ __ADD(RTNL_BRIDGE_ROOT_BLOCK, root_block),
+ __ADD(RTNL_BRIDGE_FAST_LEAVE, fast_leave),
+ __ADD(RTNL_BRIDGE_UNICAST_FLOOD, flood),
+ __ADD(RTNL_BRIDGE_LEARNING, learning),
+ __ADD(RTNL_BRIDGE_LEARNING_SYNC, learning_sync),
};
/**
@@ -503,6 +867,101 @@ int rtnl_link_bridge_str2flags(const char *name)
/** @} */
+static const struct trans_tbl port_states[] = {
+ __ADD(BR_STATE_DISABLED, disabled),
+ __ADD(BR_STATE_LISTENING, listening),
+ __ADD(BR_STATE_LEARNING, learning),
+ __ADD(BR_STATE_FORWARDING, forwarding),
+ __ADD(BR_STATE_BLOCKING, blocking),
+};
+
+/**
+ * @name Port State Translation
+ * @{
+ */
+
+char *rtnl_link_bridge_portstate2str(int st, char *buf, size_t len)
+{
+ return __type2str(st, buf, len, port_states, ARRAY_SIZE(port_states));
+}
+
+int rtnl_link_bridge_str2portstate(const char *name)
+{
+ return __str2type(name, port_states, ARRAY_SIZE(port_states));
+}
+
+/** @} */
+
+static const struct trans_tbl hw_modes[] = {
+ __ADD(RTNL_BRIDGE_HWMODE_VEB, veb),
+ __ADD(RTNL_BRIDGE_HWMODE_VEPA, vepa),
+ __ADD(RTNL_BRIDGE_HWMODE_UNDEF, undef),
+};
+
+/**
+ * @name Hardware Mode Translation
+ * @{
+ */
+
+char *rtnl_link_bridge_hwmode2str(uint16_t st, char *buf, size_t len) {
+ return __type2str(st, buf, len, hw_modes, ARRAY_SIZE(hw_modes));
+}
+
+uint16_t rtnl_link_bridge_str2hwmode(const char *name)
+{
+ return __str2type(name, hw_modes, ARRAY_SIZE(hw_modes));
+}
+
+/** @} */
+
+int rtnl_link_bridge_pvid(struct rtnl_link *link)
+{
+ struct bridge_data *bd;
+
+ IS_BRIDGE_LINK_ASSERT(link);
+
+ bd = link->l_af_data[AF_BRIDGE];
+ if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN)
+ return (int) bd->vlan_info.pvid;
+
+ return -EINVAL;
+}
+
+int rtnl_link_bridge_has_vlan(struct rtnl_link *link)
+{
+ struct bridge_data *bd;
+ int i;
+
+ IS_BRIDGE_LINK_ASSERT(link);
+
+ bd = link->l_af_data[AF_BRIDGE];
+ if (bd->ce_mask & BRIDGE_ATTR_PORT_VLAN) {
+ if (bd->vlan_info.pvid)
+ return 1;
+
+ for (i = 0; i < RTNL_LINK_BRIDGE_VLAN_BITMAP_LEN; ++i) {
+ if (bd->vlan_info.vlan_bitmap[i] ||
+ bd->vlan_info.untagged_bitmap[i])
+ return 1;
+ }
+ }
+ return 0;
+}
+
+struct rtnl_link_bridge_vlan *rtnl_link_bridge_get_port_vlan(struct rtnl_link *link)
+{
+ struct bridge_data *data;
+
+ if (!rtnl_link_is_bridge(link))
+ return NULL;
+
+ data = link->l_af_data[AF_BRIDGE];
+ if (data && (data->ce_mask & BRIDGE_ATTR_PORT_VLAN))
+ return &data->vlan_info;
+
+ return NULL;
+}
+
static struct rtnl_link_af_ops bridge_ops = {
.ao_family = AF_BRIDGE,
.ao_alloc = &bridge_alloc,
@@ -511,6 +970,13 @@ static struct rtnl_link_af_ops bridge_ops = {
.ao_parse_protinfo = &bridge_parse_protinfo,
.ao_dump[NL_DUMP_DETAILS] = &bridge_dump_details,
.ao_compare = &bridge_compare,
+ .ao_parse_af_full = &bridge_parse_af_full,
+ .ao_get_af = &bridge_get_af,
+ .ao_fill_af = &bridge_fill_af,
+ .ao_fill_pi = &bridge_fill_pi,
+ .ao_fill_pi_flags = NLA_F_NESTED,
+ .ao_override_rtm = &bridge_override_rtm,
+ .ao_fill_af_no_nest = 1,
};
static void __init bridge_init(void)
diff --git a/lib/route/link/can.c b/lib/route/link/can.c
index 60da42db..884121f9 100644
--- a/lib/route/link/can.c
+++ b/lib/route/link/can.c
@@ -73,11 +73,15 @@ static int can_alloc(struct rtnl_link *link)
{
struct can_info *ci;
- ci = calloc(1, sizeof(*ci));
- if (!ci)
- return -NLE_NOMEM;
-
- link->l_info = ci;
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*ci));
+ else {
+ ci = calloc(1, sizeof(*ci));
+ if (!ci)
+ return -NLE_NOMEM;
+
+ link->l_info = ci;
+ }
return 0;
}
@@ -89,7 +93,7 @@ static int can_parse(struct rtnl_link *link, struct nlattr *data,
struct can_info *ci;
int err;
- NL_DBG(3, "Parsing CAN link info");
+ NL_DBG(3, "Parsing CAN link info\n");
if ((err = nla_parse_nested(tb, IFLA_CAN_MAX, data, can_policy)) < 0)
goto errout;
@@ -751,11 +755,11 @@ int rtnl_link_can_unset_ctrlmode(struct rtnl_link *link, uint32_t ctrlmode)
*/
static const struct trans_tbl can_ctrlmode[] = {
- __ADD(CAN_CTRLMODE_LOOPBACK, loopback)
- __ADD(CAN_CTRLMODE_LISTENONLY, listen-only)
- __ADD(CAN_CTRLMODE_3_SAMPLES, triple-sampling)
- __ADD(CAN_CTRLMODE_ONE_SHOT, one-shot)
- __ADD(CAN_CTRLMODE_BERR_REPORTING, berr-reporting)
+ __ADD(CAN_CTRLMODE_LOOPBACK, loopback),
+ __ADD(CAN_CTRLMODE_LISTENONLY, listen-only),
+ __ADD(CAN_CTRLMODE_3_SAMPLES, triple-sampling),
+ __ADD(CAN_CTRLMODE_ONE_SHOT, one-shot),
+ __ADD(CAN_CTRLMODE_BERR_REPORTING, berr-reporting),
};
char *rtnl_link_can_ctrlmode2str(int ctrlmode, char *buf, size_t len)
diff --git a/lib/route/link/geneve.c b/lib/route/link/geneve.c
new file mode 100644
index 00000000..7232b07f
--- /dev/null
+++ b/lib/route/link/geneve.c
@@ -0,0 +1,810 @@
+/*
+ * lib/route/link/geneve.c Geneve Link Info
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2018 Wang Jian <jianjian.wang1@gmail.com>
+ */
+/**
+ * @ingroup link
+ * @defgroup geneve Geneve
+ * Generic Network Virtualization Encapsulation
+ *
+ * @details
+ * \b Link Type Name: "geneve"
+ *
+ * @route_doc{link_geneve, Geneve Documentation}
+ *
+ * @{
+ */
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink-private/route/link/api.h>
+#include <netlink/route/link/geneve.h>
+
+
+/** @cond SKIP */
+#define GENEVE_ATTR_ID (1<<0)
+#define GENEVE_ATTR_REMOTE (1<<1)
+#define GENEVE_ATTR_REMOTE6 (1<<2)
+#define GENEVE_ATTR_TTL (1<<3)
+#define GENEVE_ATTR_TOS (1<<4)
+#define GENEVE_ATTR_LABEL (1<<5)
+#define GENEVE_ATTR_PORT (1<<6)
+#define GENEVE_ATTR_FLAGS (1<<7)
+#define GENEVE_ATTR_UDP_CSUM (1<<8)
+#define GENEVE_ATTR_UDP_ZERO_CSUM6_TX (1<<9)
+#define GENEVE_ATTR_UDP_ZERO_CSUM6_RX (1<<10)
+
+struct geneve_info
+{
+ uint32_t id;
+ uint32_t remote;
+ struct in6_addr remote6;
+ uint8_t ttl;
+ uint8_t tos;
+ uint32_t label;
+ uint16_t port;
+ uint8_t flags;
+ uint8_t udp_csum;
+ uint8_t udp_zero_csum6_tx;
+ uint8_t udp_zero_csum6_rx;
+ uint32_t mask;
+};
+
+/** @endcond */
+
+static struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = {
+ [IFLA_GENEVE_ID] = { .type = NLA_U32 },
+ [IFLA_GENEVE_REMOTE] = { .minlen = sizeof(uint32_t) },
+ [IFLA_GENEVE_REMOTE6] = { .minlen = sizeof(struct in6_addr) },
+ [IFLA_GENEVE_TTL] = { .type = NLA_U8 },
+ [IFLA_GENEVE_TOS] = { .type = NLA_U8 },
+ [IFLA_GENEVE_LABEL] = { .type = NLA_U32 },
+ [IFLA_GENEVE_PORT] = { .type = NLA_U16 },
+ [IFLA_GENEVE_COLLECT_METADATA] = { .type = NLA_FLAG },
+ [IFLA_GENEVE_UDP_CSUM] = { .type = NLA_U8 },
+ [IFLA_GENEVE_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
+ [IFLA_GENEVE_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
+};
+
+static int geneve_alloc(struct rtnl_link *link)
+{
+ struct geneve_info *geneve;
+
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*geneve));
+ else {
+ if ((geneve = calloc(1, sizeof(*geneve))) == NULL)
+ return -NLE_NOMEM;
+ link->l_info = geneve;
+ }
+
+ return 0;
+}
+
+static int geneve_parse(struct rtnl_link *link, struct nlattr *data,
+ struct nlattr *xstats)
+{
+ struct nlattr *tb[IFLA_GENEVE_MAX + 1];
+ struct geneve_info *geneve;
+ int err = 0;
+
+ NL_DBG(3, "Parsing Geneve link info\n");
+
+ err = nla_parse_nested(tb, IFLA_GENEVE_MAX, data, geneve_policy);
+ if (err < 0)
+ return err;
+
+ err = geneve_alloc(link);
+ if (err < 0)
+ return err;
+
+ geneve = link->l_info;
+
+ if (tb[IFLA_GENEVE_ID]) {
+ geneve->id = nla_get_u32(tb[IFLA_GENEVE_ID]);
+ geneve->mask |= GENEVE_ATTR_ID;
+ }
+
+ if (tb[IFLA_GENEVE_REMOTE]) {
+ nla_memcpy(&geneve->remote, tb[IFLA_GENEVE_REMOTE],
+ sizeof(geneve->remote));
+ geneve->mask |= GENEVE_ATTR_REMOTE;
+ geneve->mask &= ~GENEVE_ATTR_REMOTE6;
+ }
+ if (tb[IFLA_GENEVE_REMOTE6]) {
+ nla_memcpy(&geneve->remote6, tb[IFLA_GENEVE_REMOTE6],
+ sizeof(geneve->remote6));
+ geneve->mask |= GENEVE_ATTR_REMOTE6;
+ geneve->mask &= ~GENEVE_ATTR_REMOTE;
+ }
+
+ if (tb[IFLA_GENEVE_TTL]) {
+ geneve->ttl = nla_get_u8(tb[IFLA_GENEVE_TTL]);
+ geneve->mask |= GENEVE_ATTR_TTL;
+ }
+
+ if (tb[IFLA_GENEVE_TOS]) {
+ geneve->tos = nla_get_u8(tb[IFLA_GENEVE_TOS]);
+ geneve->mask |= GENEVE_ATTR_TOS;
+ }
+
+ if (tb[IFLA_GENEVE_LABEL]) {
+ geneve->label = nla_get_u32(tb[IFLA_GENEVE_LABEL]);
+ geneve->mask |= GENEVE_ATTR_LABEL;
+ }
+
+ if (tb[IFLA_GENEVE_PORT]) {
+ geneve->port = nla_get_u16(tb[IFLA_GENEVE_PORT]);
+ geneve->mask |= GENEVE_ATTR_PORT;
+ }
+
+ if (tb[IFLA_GENEVE_COLLECT_METADATA])
+ geneve->flags |= RTNL_LINK_GENEVE_F_COLLECT_METADATA;
+
+ if (tb[IFLA_GENEVE_UDP_CSUM]) {
+ geneve->udp_csum = nla_get_u8(tb[IFLA_GENEVE_UDP_CSUM]);
+ geneve->mask |= GENEVE_ATTR_UDP_CSUM;
+ }
+
+ if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]) {
+ geneve->udp_zero_csum6_tx = nla_get_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_TX]);
+ geneve->mask |= GENEVE_ATTR_UDP_ZERO_CSUM6_TX;
+ }
+
+ if (tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]) {
+ geneve->udp_zero_csum6_rx = nla_get_u8(tb[IFLA_GENEVE_UDP_ZERO_CSUM6_RX]);
+ geneve->mask |= GENEVE_ATTR_UDP_ZERO_CSUM6_RX;
+ }
+
+ return err;
+}
+
+static void geneve_free(struct rtnl_link *link)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ free(geneve);
+ link->l_info = NULL;
+}
+
+static void geneve_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ nl_dump(p, "geneve-id %u", geneve->id);
+}
+
+static void geneve_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ struct geneve_info *geneve = link->l_info;
+ char addr[INET6_ADDRSTRLEN];
+
+ nl_dump_line(p, " geneve-id %u\n", geneve->id);
+
+ if (geneve->mask & GENEVE_ATTR_REMOTE) {
+ nl_dump(p, " remote ");
+ if (inet_ntop(AF_INET, &geneve->remote, addr, sizeof(addr)))
+ nl_dump_line(p, "%s\n", addr);
+ else
+ nl_dump_line(p, "%#x\n", ntohs(geneve->remote));
+ } else if (geneve->mask & GENEVE_ATTR_REMOTE6) {
+ nl_dump(p, " remote ");
+ if (inet_ntop(AF_INET6, &geneve->remote6, addr, sizeof(addr)))
+ nl_dump_line(p, "%s\n", addr);
+ else
+ nl_dump_line(p, "%#x\n", geneve->remote6);
+ }
+
+ if (geneve->mask & GENEVE_ATTR_TTL) {
+ nl_dump(p, " ttl ");
+ nl_dump_line(p, "%u\n", geneve->ttl);
+ }
+
+ if (geneve->mask & GENEVE_ATTR_TOS) {
+ nl_dump(p, " tos ");
+ nl_dump_line(p, "%u\n", geneve->tos);
+ }
+
+ if (geneve->mask & GENEVE_ATTR_PORT) {
+ nl_dump(p, " port ");
+ nl_dump_line(p, "%u\n", ntohs(geneve->port));
+ }
+
+ if (geneve->mask & GENEVE_ATTR_LABEL) {
+ nl_dump(p, " label ");
+ nl_dump_line(p, "%u\n", ntohl(geneve->label));
+ }
+
+ if (geneve->mask & GENEVE_ATTR_UDP_CSUM) {
+ nl_dump(p, " UDP checksum ");
+ if (geneve->udp_csum)
+ nl_dump_line(p, "enabled (%#x)\n", geneve->udp_csum);
+ else
+ nl_dump_line(p, "disabled\n");
+ }
+
+ if (geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_TX) {
+ nl_dump(p, " udp-zero-csum6-tx ");
+ if (geneve->udp_zero_csum6_tx)
+ nl_dump_line(p, "enabled (%#x)\n", geneve->udp_zero_csum6_tx);
+ else
+ nl_dump_line(p, "disabled\n");
+ }
+
+ if (geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_RX) {
+ nl_dump(p, " udp-zero-csum6-rx ");
+ if (geneve->udp_zero_csum6_tx)
+ nl_dump_line(p, "enabled (%#x)\n", geneve->udp_zero_csum6_rx);
+ else
+ nl_dump_line(p, "disabled\n");
+ }
+
+ if (geneve->flags & RTNL_LINK_GENEVE_F_COLLECT_METADATA)
+ nl_dump(p, " collect-metadata\n");
+}
+
+static int geneve_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+ struct geneve_info *gdst, *gsrc;
+ int err;
+
+ gsrc = src->l_info;
+ dst->l_info = NULL;
+ err = rtnl_link_set_type(dst, "geneve");
+ if (err < 0)
+ return err;
+
+ gdst = dst->l_info;
+
+ if (!gsrc || !gdst)
+ return -NLE_NOMEM;
+
+ memcpy(gdst, gsrc, sizeof(struct geneve_info));
+
+ return 0;
+}
+
+static int geneve_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+ struct geneve_info *geneve = link->l_info;
+ struct nlattr *data;
+
+ if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+ return -NLE_MSGSIZE;
+
+ if (geneve->mask & GENEVE_ATTR_ID)
+ NLA_PUT_U32(msg, IFLA_GENEVE_ID, geneve->id);
+
+ if (geneve->mask & GENEVE_ATTR_REMOTE)
+ NLA_PUT(msg, IFLA_GENEVE_REMOTE,
+ sizeof(geneve->remote), &geneve->remote);
+
+ if (geneve->mask & GENEVE_ATTR_REMOTE6)
+ NLA_PUT(msg, IFLA_GENEVE_REMOTE6,
+ sizeof(geneve->remote6), &geneve->remote6);
+
+ if (geneve->mask & GENEVE_ATTR_TTL)
+ NLA_PUT_U8(msg, IFLA_GENEVE_TTL, geneve->ttl);
+
+ if (geneve->mask & GENEVE_ATTR_TOS)
+ NLA_PUT_U8(msg, IFLA_GENEVE_TOS, geneve->tos);
+
+ if (geneve->mask & GENEVE_ATTR_LABEL)
+ NLA_PUT_U32(msg, IFLA_GENEVE_LABEL, geneve->label);
+
+ if (geneve->mask & GENEVE_ATTR_PORT)
+ NLA_PUT_U32(msg, IFLA_GENEVE_PORT, geneve->port);
+
+ if (geneve->mask & GENEVE_ATTR_UDP_CSUM)
+ NLA_PUT_U8(msg, IFLA_GENEVE_UDP_CSUM, geneve->udp_csum);
+
+ if (geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_TX)
+ NLA_PUT_U8(msg, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, geneve->udp_zero_csum6_tx);
+
+ if (geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_RX)
+ NLA_PUT_U8(msg, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, geneve->udp_zero_csum6_rx);
+
+ if (geneve->flags & RTNL_LINK_GENEVE_F_COLLECT_METADATA)
+ NLA_PUT_FLAG(msg, IFLA_GENEVE_COLLECT_METADATA);
+
+ nla_nest_end(msg, data);
+
+nla_put_failure:
+
+ return 0;
+}
+
+static struct rtnl_link_info_ops geneve_info_ops = {
+ .io_name = "geneve",
+ .io_alloc = geneve_alloc,
+ .io_parse = geneve_parse,
+ .io_dump = {
+ [NL_DUMP_LINE] = geneve_dump_line,
+ [NL_DUMP_DETAILS] = geneve_dump_details,
+ },
+ .io_clone = geneve_clone,
+ .io_put_attrs = geneve_put_attrs,
+ .io_free = geneve_free,
+};
+
+
+/** @cond SKIP */
+#define IS_GENEVE_LINK_ASSERT(link) \
+ if ((link)->l_info_ops != &geneve_info_ops) { \
+ APPBUG("Link is not a geneve link. set type \"geneve\" first."); \
+ return -NLE_OPNOTSUPP; \
+ }
+/** @endcond */
+
+/**
+ * @name Geneve Object
+ * @{
+ */
+
+/**
+ * Allocate link object of type Geneve
+ *
+ * @return Allocated link object or NULL.
+ */
+struct rtnl_link *rtnl_link_geneve_alloc(void)
+{
+ struct rtnl_link *link;
+ int err;
+
+ if (!(link = rtnl_link_alloc()))
+ return NULL;
+
+ if ((err = rtnl_link_set_type(link, "geneve")) < 0) {
+ rtnl_link_put(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/**
+ * Check if link is a Geneve link
+ * @arg link Link object
+ *
+ * @return True if link is a Geneve link, otherwisee false is returned.
+ */
+int rtnl_link_is_geneve(struct rtnl_link *link)
+{
+ return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "geneve");
+}
+
+/**
+ * Set Geneve Network Indentifier
+ * @arg link Link object
+ * @arg id Geneve network identifier
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_id(struct rtnl_link *link, uint32_t id)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if (id > RTNL_GENEVE_ID_MAX)
+ return -NLE_INVAL;
+
+ geneve->id = id;
+ geneve->mask |= GENEVE_ATTR_ID;
+
+ return 0;
+}
+
+/**
+ * Get Geneve Network Identifier
+ * @arg link Link object
+ * @arg id Pointer to store network identifier
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_get_id(struct rtnl_link *link, uint32_t *id)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if (!id)
+ return -NLE_INVAL;
+
+ if (geneve->mask & GENEVE_ATTR_ID)
+ *id = geneve->id;
+ else
+ return -NLE_AGAIN;
+
+ return 0;
+}
+
+/**
+ * Set Geneve unicast destination IP address
+ * @arg link Link object
+ * @arg addr The unicast destination IP address
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_remote(struct rtnl_link *link, struct nl_addr *addr)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if ((nl_addr_get_family(addr) == AF_INET) &&
+ (nl_addr_get_len(addr) == sizeof(geneve->remote))) {
+ memcpy(&geneve->remote, nl_addr_get_binary_addr(addr),
+ sizeof(geneve->remote));
+ geneve->mask |= GENEVE_ATTR_REMOTE;
+ geneve->mask &= ~GENEVE_ATTR_REMOTE6;
+ } else if ((nl_addr_get_family(addr) == AF_INET6) &&
+ (nl_addr_get_len(addr) == sizeof(geneve->remote6))) {
+ memcpy(&geneve->remote6, nl_addr_get_binary_addr(addr),
+ sizeof(geneve->remote6));
+ geneve->mask |= GENEVE_ATTR_REMOTE6;
+ geneve->mask &= ~GENEVE_ATTR_REMOTE;
+ } else
+ return -NLE_INVAL;
+
+ return 0;
+}
+
+/**
+ * Get Geneve unicast destination IP address
+ * @arg link Link object
+ * @arg addr Pointer to store unicast destination IP addree
+ *
+ * @return 0 on success or a a negative error code
+ */
+int rtnl_link_geneve_get_remote(struct rtnl_link *link, struct nl_addr **addr)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if (!addr)
+ return -NLE_INVAL;
+
+ if (geneve->mask & GENEVE_ATTR_REMOTE)
+ *addr = nl_addr_build(AF_INET, &geneve->remote, sizeof(geneve->remote));
+ else if (geneve->mask & GENEVE_ATTR_REMOTE6)
+ *addr = nl_addr_build(AF_INET6, &geneve->remote6, sizeof(geneve->remote6));
+ else
+ return -NLE_AGAIN;
+
+ return 0;
+}
+
+/**
+ * Set IP TTL value to use for Geneve
+ * @arg link Link object
+ * @arg ttl TTL value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_ttl(struct rtnl_link *link, uint8_t ttl)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ geneve->ttl = ttl;
+ geneve->mask |= GENEVE_ATTR_TTL;
+
+ return 0;
+}
+
+/**
+ * Get IP TTL value to use for Geneve
+ * @arg link Link object
+ *
+ * @return TTL value on success or a negative error code
+ */
+int rtnl_link_geneve_get_ttl(struct rtnl_link *link)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if (!(geneve->mask & GENEVE_ATTR_TTL))
+ return -NLE_AGAIN;
+
+ return geneve->ttl;
+}
+
+/**
+ * Set IP ToS value to use for Geneve
+ * @arg link Link object
+ * @arg tos ToS value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_tos(struct rtnl_link *link, uint8_t tos)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ geneve->tos = tos;
+ geneve->mask |= GENEVE_ATTR_TOS;
+
+ return 0;
+}
+
+/**
+ * Get IP ToS value to use for Geneve
+ * @arg link Link object
+ *
+ * @return ToS value on success or a negative error code
+ */
+int rtnl_link_geneve_get_tos(struct rtnl_link *link)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if (!(geneve->mask & GENEVE_ATTR_TOS))
+ return -NLE_AGAIN;
+
+ return geneve->tos;
+}
+
+/**
+ * Set UDP destination port to use for Geneve
+ * @arg link Link object
+ * @arg port Destination port
+ *
+ * @return 0 on success or a negative error code
+ */
+
+int rtnl_link_geneve_set_port(struct rtnl_link *link, uint32_t port)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ geneve->port = htons(port);
+ geneve->mask |= GENEVE_ATTR_PORT;
+
+ return 0;
+}
+
+/**
+ * Get UDP destination port to use for Geneve
+ * @arg link Link object
+ * @arg port Pointer to store destination port
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_get_port(struct rtnl_link *link, uint32_t *port)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if (!port)
+ return -NLE_INVAL;
+
+ if (!(geneve->mask & GENEVE_ATTR_PORT))
+ return -NLE_NOATTR;
+
+ *port = ntohs(geneve->port);
+
+ return 0;
+}
+
+/**
+ * Set flow label to use for Geneve
+ * @arg link Link object
+ * @arg label Destination label
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_label(struct rtnl_link *link, uint32_t label)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ geneve->label = htonl(label);
+ geneve->mask |= GENEVE_ATTR_LABEL;
+
+ return 0;
+}
+
+/**
+ * Get flow label to use for Geneve
+ * @arg link Link object
+ * @arg label Pointer to store destination label
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_get_label(struct rtnl_link *link, uint32_t *label)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if (!label)
+ return -NLE_INVAL;
+ if (!(geneve->mask & GENEVE_ATTR_LABEL))
+ return -NLE_NOATTR;
+
+ *label = ntohl(geneve->label);
+
+ return 0;
+}
+
+/**
+ * Set UDP checksum status to use for Geneve
+ * @arg link Link object
+ * @arg csum Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_udp_csum(struct rtnl_link *link, uint8_t csum)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ geneve->udp_csum = csum;
+ geneve->mask |= GENEVE_ATTR_UDP_CSUM;
+
+ return 0;
+}
+
+/**
+ * Get UDP checksum status to use for Geneve
+ * @arg link Link object
+ *
+ * @return status value on success or a negative error code
+ */
+int rtnl_link_geneve_get_udp_csum(struct rtnl_link *link)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if (!(geneve->mask & GENEVE_ATTR_UDP_CSUM))
+ return -NLE_NOATTR;
+
+ return geneve->udp_csum;
+}
+
+/**
+ * Set skip UDP checksum transmitted over IPv6 status to use for Geneve
+ * @arg link Link object
+ * @arg csum Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_udp_zero_csum6_tx(struct rtnl_link *link, uint8_t csum)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ geneve->udp_zero_csum6_tx = csum;
+ geneve->mask |= GENEVE_ATTR_UDP_ZERO_CSUM6_TX;
+
+ return 0;
+}
+
+/**
+ * Get skip UDP checksum transmitted over IPv6 status to use for Geneve
+ * @arg link Link object
+ *
+ * @return Status value on success or a negative error code
+ */
+int rtnl_link_geneve_get_udp_zero_csum6_tx(struct rtnl_link *link)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if (!(geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_TX))
+ return -NLE_NOATTR;
+
+ return geneve->udp_zero_csum6_tx;
+}
+
+/**
+ * Set skip UDP checksum received over IPv6 status to use for Geneve
+ * @arg link Link object
+ * @arg csum Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_udp_zero_csum6_rx(struct rtnl_link *link, uint8_t csum)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ geneve->udp_zero_csum6_rx = csum;
+ geneve->mask |= GENEVE_ATTR_UDP_ZERO_CSUM6_RX;
+
+ return 0;
+}
+
+/**
+ * Get skip UDP checksum received over IPv6 status to use for Geneve
+ * @arg link Link object
+ *
+ * @return Status value on success or a negative error code
+ */
+int rtnl_link_geneve_get_udp_zero_csum6_rx(struct rtnl_link *link)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if (!(geneve->mask & GENEVE_ATTR_UDP_ZERO_CSUM6_RX))
+ return -NLE_NOATTR;
+
+ return geneve->udp_zero_csum6_rx;
+}
+
+/**
+ * Set Geneve flags
+ * @arg link Link object
+ * @arg flags Which flags to set
+ * @arg enable Boolean enabling or disabling flag
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_set_flags(struct rtnl_link *link, uint8_t flags, int enable)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ if (flags & ~RTNL_LINK_GENEVE_F_COLLECT_METADATA)
+ return -NLE_INVAL;
+
+ if (enable)
+ geneve->flags = flags;
+ else
+ geneve->flags &= ~flags;
+
+ return 0;
+}
+
+/**
+ * Get Geneve flags
+ * @arg link Link object
+ * @arg flags Pointer to store flags
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_geneve_get_flags(struct rtnl_link *link, uint8_t *flags)
+{
+ struct geneve_info *geneve = link->l_info;
+
+ IS_GENEVE_LINK_ASSERT(link);
+
+ *flags = geneve->flags;
+ return 0;
+}
+
+/** @} */
+static void __init geneve_init(void)
+{
+ rtnl_link_register_info(&geneve_info_ops);
+}
+
+static void __exit geneve_exit(void)
+{
+ rtnl_link_unregister_info(&geneve_info_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/ifb.c b/lib/route/link/ifb.c
new file mode 100644
index 00000000..524f5c6a
--- /dev/null
+++ b/lib/route/link/ifb.c
@@ -0,0 +1,40 @@
+/*
+ * lib/route/link/ifb.c IFB Interfaces
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2014 Cong Wang <xiyou.wangcong@gmail.com>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup ifb Intermediate Functional Block
+ *
+ * @details
+ * \b Link Type Name: "ifb"
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink-private/route/link/api.h>
+
+static struct rtnl_link_info_ops ifb_info_ops = {
+ .io_name = "ifb",
+};
+
+static void __init ifb_init(void)
+{
+ rtnl_link_register_info(&ifb_info_ops);
+}
+
+static void __exit ifb_exit(void)
+{
+ rtnl_link_unregister_info(&ifb_info_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/inet.c b/lib/route/link/inet.c
index e94342f8..6651bc38 100644
--- a/lib/route/link/inet.c
+++ b/lib/route/link/inet.c
@@ -61,6 +61,7 @@
#include <netlink/netlink.h>
#include <netlink/attr.h>
#include <netlink/route/rtnl.h>
+#include <netlink/route/link/inet.h>
#include <netlink-private/route/link/api.h>
/** @cond SKIP */
@@ -91,7 +92,7 @@ static void inet_free(struct rtnl_link *link, void *data)
free(data);
}
-static struct nla_policy inet_policy[IFLA_INET6_MAX+1] = {
+static struct nla_policy inet_policy[IFLA_INET_MAX+1] = {
[IFLA_INET_CONF] = { .minlen = 4 },
};
@@ -141,34 +142,34 @@ nla_put_failure:
}
static const struct trans_tbl inet_devconf[] = {
- __ADD(IPV4_DEVCONF_FORWARDING, forwarding)
- __ADD(IPV4_DEVCONF_MC_FORWARDING, mc_forwarding)
- __ADD(IPV4_DEVCONF_PROXY_ARP, proxy_arp)
- __ADD(IPV4_DEVCONF_ACCEPT_REDIRECTS, accept_redirects)
- __ADD(IPV4_DEVCONF_SECURE_REDIRECTS, secure_redirects)
- __ADD(IPV4_DEVCONF_SEND_REDIRECTS, send_redirects)
- __ADD(IPV4_DEVCONF_SHARED_MEDIA, shared_media)
- __ADD(IPV4_DEVCONF_RP_FILTER, rp_filter)
- __ADD(IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route)
- __ADD(IPV4_DEVCONF_BOOTP_RELAY, bootp_relay)
- __ADD(IPV4_DEVCONF_LOG_MARTIANS, log_martians)
- __ADD(IPV4_DEVCONF_TAG, tag)
- __ADD(IPV4_DEVCONF_ARPFILTER, arpfilter)
- __ADD(IPV4_DEVCONF_MEDIUM_ID, medium_id)
- __ADD(IPV4_DEVCONF_NOXFRM, noxfrm)
- __ADD(IPV4_DEVCONF_NOPOLICY, nopolicy)
- __ADD(IPV4_DEVCONF_FORCE_IGMP_VERSION, force_igmp_version)
- __ADD(IPV4_DEVCONF_ARP_ANNOUNCE, arp_announce)
- __ADD(IPV4_DEVCONF_ARP_IGNORE, arp_ignore)
- __ADD(IPV4_DEVCONF_PROMOTE_SECONDARIES, promote_secondaries)
- __ADD(IPV4_DEVCONF_ARP_ACCEPT, arp_accept)
- __ADD(IPV4_DEVCONF_ARP_NOTIFY, arp_notify)
- __ADD(IPV4_DEVCONF_ACCEPT_LOCAL, accept_local)
- __ADD(IPV4_DEVCONF_SRC_VMARK, src_vmark)
- __ADD(IPV4_DEVCONF_PROXY_ARP_PVLAN, proxy_arp_pvlan)
- __ADD(IPV4_DEVCONF_ROUTE_LOCALNET, route_localnet)
- __ADD(IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL, igmpv2_unsolicited_report_interval)
- __ADD(IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL, igmpv3_unsolicited_report_interval)
+ __ADD(IPV4_DEVCONF_FORWARDING, forwarding),
+ __ADD(IPV4_DEVCONF_MC_FORWARDING, mc_forwarding),
+ __ADD(IPV4_DEVCONF_PROXY_ARP, proxy_arp),
+ __ADD(IPV4_DEVCONF_ACCEPT_REDIRECTS, accept_redirects),
+ __ADD(IPV4_DEVCONF_SECURE_REDIRECTS, secure_redirects),
+ __ADD(IPV4_DEVCONF_SEND_REDIRECTS, send_redirects),
+ __ADD(IPV4_DEVCONF_SHARED_MEDIA, shared_media),
+ __ADD(IPV4_DEVCONF_RP_FILTER, rp_filter),
+ __ADD(IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route),
+ __ADD(IPV4_DEVCONF_BOOTP_RELAY, bootp_relay),
+ __ADD(IPV4_DEVCONF_LOG_MARTIANS, log_martians),
+ __ADD(IPV4_DEVCONF_TAG, tag),
+ __ADD(IPV4_DEVCONF_ARPFILTER, arpfilter),
+ __ADD(IPV4_DEVCONF_MEDIUM_ID, medium_id),
+ __ADD(IPV4_DEVCONF_NOXFRM, noxfrm),
+ __ADD(IPV4_DEVCONF_NOPOLICY, nopolicy),
+ __ADD(IPV4_DEVCONF_FORCE_IGMP_VERSION, force_igmp_version),
+ __ADD(IPV4_DEVCONF_ARP_ANNOUNCE, arp_announce),
+ __ADD(IPV4_DEVCONF_ARP_IGNORE, arp_ignore),
+ __ADD(IPV4_DEVCONF_PROMOTE_SECONDARIES, promote_secondaries),
+ __ADD(IPV4_DEVCONF_ARP_ACCEPT, arp_accept),
+ __ADD(IPV4_DEVCONF_ARP_NOTIFY, arp_notify),
+ __ADD(IPV4_DEVCONF_ACCEPT_LOCAL, accept_local),
+ __ADD(IPV4_DEVCONF_SRC_VMARK, src_vmark),
+ __ADD(IPV4_DEVCONF_PROXY_ARP_PVLAN, proxy_arp_pvlan),
+ __ADD(IPV4_DEVCONF_ROUTE_LOCALNET, route_localnet),
+ __ADD(IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL, igmpv2_unsolicited_report_interval),
+ __ADD(IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL, igmpv3_unsolicited_report_interval),
};
const char *rtnl_link_inet_devconf2str(int type, char *buf, size_t len)
@@ -242,7 +243,7 @@ int rtnl_link_inet_get_conf(struct rtnl_link *link, const unsigned int cfgid,
if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
return -NLE_RANGE;
- if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
+ if (!(id = rtnl_link_af_data(link, &inet_ops)))
return -NLE_NOATTR;
if (!id->i_confset[cfgid - 1])
diff --git a/lib/route/link/inet6.c b/lib/route/link/inet6.c
index 6fa2741c..f02792c8 100644
--- a/lib/route/link/inet6.c
+++ b/lib/route/link/inet6.c
@@ -13,18 +13,31 @@
#include <netlink/netlink.h>
#include <netlink/attr.h>
#include <netlink/route/rtnl.h>
+#include <netlink/route/link/inet6.h>
#include <netlink-private/route/link/api.h>
+#include "netlink-private/utils.h"
+
+#define I6_ADDR_GEN_MODE_UNKNOWN UINT8_MAX
+
struct inet6_data
{
uint32_t i6_flags;
struct ifla_cacheinfo i6_cacheinfo;
uint32_t i6_conf[DEVCONF_MAX];
+ struct in6_addr i6_token;
+ uint8_t i6_addr_gen_mode;
};
static void *inet6_alloc(struct rtnl_link *link)
{
- return calloc(1, sizeof(struct inet6_data));
+ struct inet6_data *i6;
+
+ i6 = calloc(1, sizeof(struct inet6_data));
+ if (i6)
+ i6->i6_addr_gen_mode = I6_ADDR_GEN_MODE_UNKNOWN;
+
+ return i6;
}
static void *inet6_clone(struct rtnl_link *link, void *data)
@@ -43,11 +56,13 @@ static void inet6_free(struct rtnl_link *link, void *data)
}
static struct nla_policy inet6_policy[IFLA_INET6_MAX+1] = {
- [IFLA_INET6_FLAGS] = { .type = NLA_U32 },
- [IFLA_INET6_CACHEINFO] = { .minlen = sizeof(struct ifla_cacheinfo) },
- [IFLA_INET6_CONF] = { .minlen = 4 },
- [IFLA_INET6_STATS] = { .minlen = 8 },
- [IFLA_INET6_ICMP6STATS] = { .minlen = 8 },
+ [IFLA_INET6_FLAGS] = { .type = NLA_U32 },
+ [IFLA_INET6_CACHEINFO] = { .minlen = sizeof(struct ifla_cacheinfo) },
+ [IFLA_INET6_CONF] = { .minlen = 4 },
+ [IFLA_INET6_STATS] = { .minlen = 8 },
+ [IFLA_INET6_ICMP6STATS] = { .minlen = 8 },
+ [IFLA_INET6_TOKEN] = { .minlen = sizeof(struct in6_addr) },
+ [IFLA_INET6_ADDR_GEN_MODE] = { .type = NLA_U8 },
};
static const uint8_t map_stat_id_from_IPSTATS_MIB_v1[__IPSTATS_MIB_MAX] = {
@@ -155,7 +170,14 @@ static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
if (tb[IFLA_INET6_CONF])
nla_memcpy(&i6->i6_conf, tb[IFLA_INET6_CONF],
sizeof(i6->i6_conf));
-
+
+ if (tb[IFLA_INET6_TOKEN])
+ nla_memcpy(&i6->i6_token, tb[IFLA_INET6_TOKEN],
+ sizeof(struct in6_addr));
+
+ if (tb[IFLA_INET6_ADDR_GEN_MODE])
+ i6->i6_addr_gen_mode = nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE]);
+
/*
* Due to 32bit data alignment, these addresses must be copied to an
* aligned location prior to access.
@@ -200,6 +222,19 @@ static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
return 0;
}
+static int inet6_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data)
+{
+ struct inet6_data *id = data;
+
+ if (id->i6_addr_gen_mode != I6_ADDR_GEN_MODE_UNKNOWN)
+ NLA_PUT_U8(msg, IFLA_INET6_ADDR_GEN_MODE, id->i6_addr_gen_mode);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
/* These live in include/net/if_inet6.h and should be moved to include/linux */
#define IF_RA_OTHERCONF 0x80
#define IF_RA_MANAGED 0x40
@@ -208,49 +243,54 @@ static int inet6_parse_protinfo(struct rtnl_link *link, struct nlattr *attr,
#define IF_READY 0x80000000
static const struct trans_tbl inet6_flags[] = {
- __ADD(IF_RA_OTHERCONF, ra_otherconf)
- __ADD(IF_RA_MANAGED, ra_managed)
- __ADD(IF_RA_RCVD, ra_rcvd)
- __ADD(IF_RS_SENT, rs_sent)
- __ADD(IF_READY, ready)
+ __ADD(IF_RA_OTHERCONF, ra_otherconf),
+ __ADD(IF_RA_MANAGED, ra_managed),
+ __ADD(IF_RA_RCVD, ra_rcvd),
+ __ADD(IF_RS_SENT, rs_sent),
+ __ADD(IF_READY, ready),
};
-static char *inet6_flags2str(int flags, char *buf, size_t len)
+char *rtnl_link_inet6_flags2str(int flags, char *buf, size_t len)
{
return __flags2str(flags, buf, len, inet6_flags,
ARRAY_SIZE(inet6_flags));
}
+int rtnl_link_inet6_str2flags(const char *name)
+{
+ return __str2flags(name, inet6_flags, ARRAY_SIZE(inet6_flags));
+}
+
static const struct trans_tbl inet6_devconf[] = {
- __ADD(DEVCONF_FORWARDING, forwarding)
- __ADD(DEVCONF_HOPLIMIT, hoplimit)
- __ADD(DEVCONF_MTU6, mtu6)
- __ADD(DEVCONF_ACCEPT_RA, accept_ra)
- __ADD(DEVCONF_ACCEPT_REDIRECTS, accept_redirects)
- __ADD(DEVCONF_AUTOCONF, autoconf)
- __ADD(DEVCONF_DAD_TRANSMITS, dad_transmits)
- __ADD(DEVCONF_RTR_SOLICITS, rtr_solicits)
- __ADD(DEVCONF_RTR_SOLICIT_INTERVAL, rtr_solicit_interval)
- __ADD(DEVCONF_RTR_SOLICIT_DELAY, rtr_solicit_delay)
- __ADD(DEVCONF_USE_TEMPADDR, use_tempaddr)
- __ADD(DEVCONF_TEMP_VALID_LFT, temp_valid_lft)
- __ADD(DEVCONF_TEMP_PREFERED_LFT, temp_prefered_lft)
- __ADD(DEVCONF_REGEN_MAX_RETRY, regen_max_retry)
- __ADD(DEVCONF_MAX_DESYNC_FACTOR, max_desync_factor)
- __ADD(DEVCONF_MAX_ADDRESSES, max_addresses)
- __ADD(DEVCONF_FORCE_MLD_VERSION, force_mld_version)
- __ADD(DEVCONF_ACCEPT_RA_DEFRTR, accept_ra_defrtr)
- __ADD(DEVCONF_ACCEPT_RA_PINFO, accept_ra_pinfo)
- __ADD(DEVCONF_ACCEPT_RA_RTR_PREF, accept_ra_rtr_pref)
- __ADD(DEVCONF_RTR_PROBE_INTERVAL, rtr_probe_interval)
- __ADD(DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, accept_ra_rt_info)
- __ADD(DEVCONF_PROXY_NDP, proxy_ndp)
- __ADD(DEVCONF_OPTIMISTIC_DAD, optimistic_dad)
- __ADD(DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route)
- __ADD(DEVCONF_MC_FORWARDING, mc_forwarding)
- __ADD(DEVCONF_DISABLE_IPV6, disable_ipv6)
- __ADD(DEVCONF_ACCEPT_DAD, accept_dad)
- __ADD(DEVCONF_FORCE_TLLAO, force_tllao)
+ __ADD(DEVCONF_FORWARDING, forwarding),
+ __ADD(DEVCONF_HOPLIMIT, hoplimit),
+ __ADD(DEVCONF_MTU6, mtu6),
+ __ADD(DEVCONF_ACCEPT_RA, accept_ra),
+ __ADD(DEVCONF_ACCEPT_REDIRECTS, accept_redirects),
+ __ADD(DEVCONF_AUTOCONF, autoconf),
+ __ADD(DEVCONF_DAD_TRANSMITS, dad_transmits),
+ __ADD(DEVCONF_RTR_SOLICITS, rtr_solicits),
+ __ADD(DEVCONF_RTR_SOLICIT_INTERVAL, rtr_solicit_interval),
+ __ADD(DEVCONF_RTR_SOLICIT_DELAY, rtr_solicit_delay),
+ __ADD(DEVCONF_USE_TEMPADDR, use_tempaddr),
+ __ADD(DEVCONF_TEMP_VALID_LFT, temp_valid_lft),
+ __ADD(DEVCONF_TEMP_PREFERED_LFT, temp_prefered_lft),
+ __ADD(DEVCONF_REGEN_MAX_RETRY, regen_max_retry),
+ __ADD(DEVCONF_MAX_DESYNC_FACTOR, max_desync_factor),
+ __ADD(DEVCONF_MAX_ADDRESSES, max_addresses),
+ __ADD(DEVCONF_FORCE_MLD_VERSION, force_mld_version),
+ __ADD(DEVCONF_ACCEPT_RA_DEFRTR, accept_ra_defrtr),
+ __ADD(DEVCONF_ACCEPT_RA_PINFO, accept_ra_pinfo),
+ __ADD(DEVCONF_ACCEPT_RA_RTR_PREF, accept_ra_rtr_pref),
+ __ADD(DEVCONF_RTR_PROBE_INTERVAL, rtr_probe_interval),
+ __ADD(DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, accept_ra_rt_info),
+ __ADD(DEVCONF_PROXY_NDP, proxy_ndp),
+ __ADD(DEVCONF_OPTIMISTIC_DAD, optimistic_dad),
+ __ADD(DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route),
+ __ADD(DEVCONF_MC_FORWARDING, mc_forwarding),
+ __ADD(DEVCONF_DISABLE_IPV6, disable_ipv6),
+ __ADD(DEVCONF_ACCEPT_DAD, accept_dad),
+ __ADD(DEVCONF_FORCE_TLLAO, force_tllao),
};
static char *inet6_devconf2str(int type, char *buf, size_t len)
@@ -259,32 +299,59 @@ static char *inet6_devconf2str(int type, char *buf, size_t len)
ARRAY_SIZE(inet6_devconf));
}
+static const struct trans_tbl inet6_addr_gen_mode[] = {
+ __ADD(IN6_ADDR_GEN_MODE_EUI64, eui64),
+ __ADD(IN6_ADDR_GEN_MODE_NONE, none),
+ __ADD(IN6_ADDR_GEN_MODE_STABLE_PRIVACY, stable_privacy),
+};
+
+const char *rtnl_link_inet6_addrgenmode2str(uint8_t mode, char *buf, size_t len)
+{
+ return __type2str(mode, buf, len, inet6_addr_gen_mode,
+ ARRAY_SIZE(inet6_addr_gen_mode));
+}
+
+uint8_t rtnl_link_inet6_str2addrgenmode(const char *mode)
+{
+ return (uint8_t) __str2type(mode, inet6_addr_gen_mode,
+ ARRAY_SIZE(inet6_addr_gen_mode));
+}
static void inet6_dump_details(struct rtnl_link *link,
struct nl_dump_params *p, void *data)
{
struct inet6_data *i6 = data;
- char buf[64], buf2[64];
+ struct nl_addr *addr;
int i, n = 0;
+ char buf[64];
nl_dump_line(p, " ipv6 max-reasm-len %s",
- nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf)));
+ nl_size2str(i6->i6_cacheinfo.max_reasm_len, buf, sizeof(buf)));
nl_dump(p, " <%s>\n",
- inet6_flags2str(i6->i6_flags, buf, sizeof(buf)));
-
+ rtnl_link_inet6_flags2str(i6->i6_flags, buf, sizeof(buf)));
nl_dump_line(p, " create-stamp %.2fs reachable-time %s",
- (double) i6->i6_cacheinfo.tstamp / 100.,
- nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf)));
+ (double) i6->i6_cacheinfo.tstamp / 100.,
+ nl_msec2str(i6->i6_cacheinfo.reachable_time, buf, sizeof(buf)));
nl_dump(p, " retrans-time %s\n",
- nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf)));
+ nl_msec2str(i6->i6_cacheinfo.retrans_time, buf, sizeof(buf)));
+
+ addr = nl_addr_build(AF_INET6, &i6->i6_token, sizeof(i6->i6_token));
+ nl_dump(p, " token %s\n",
+ nl_addr2str(addr, buf, sizeof(buf)));
+ nl_addr_put(addr);
+
+ nl_dump(p, " link-local address mode %s\n",
+ rtnl_link_inet6_addrgenmode2str(i6->i6_addr_gen_mode,
+ buf, sizeof(buf)));
nl_dump_line(p, " devconf:\n");
nl_dump_line(p, " ");
for (i = 0; i < DEVCONF_MAX; i++) {
+ char buf2[64];
uint32_t value = i6->i6_conf[i];
int x, offset;
@@ -303,7 +370,6 @@ static void inet6_dump_details(struct rtnl_link *link,
default:
snprintf(buf2, sizeof(buf2), "%u", value);
break;
-
}
inet6_devconf2str(i, buf, sizeof(buf));
@@ -315,7 +381,7 @@ static void inet6_dump_details(struct rtnl_link *link,
for (x = strlen(buf); x < offset; x++)
buf[x] = ' ';
- strncpy(&buf[offset], buf2, strlen(buf2));
+ _nl_strncpy_trunc(&buf[offset], buf2, sizeof(buf) - offset);
nl_dump_line(p, "%s", buf);
@@ -468,11 +534,160 @@ static struct rtnl_link_af_ops inet6_ops = {
.ao_free = &inet6_free,
.ao_parse_protinfo = &inet6_parse_protinfo,
.ao_parse_af = &inet6_parse_protinfo,
+ .ao_fill_af = &inet6_fill_af,
.ao_dump[NL_DUMP_DETAILS] = &inet6_dump_details,
.ao_dump[NL_DUMP_STATS] = &inet6_dump_stats,
.ao_protinfo_policy = &protinfo_policy,
};
+/**
+ * Return IPv6 specific flags
+ * @arg link Link object
+ * @arg out_flags Flags on success
+ *
+ * Returns the link's IPv6 flags.
+ *
+ * @return 0 on success
+ * @return -NLE_NOATTR configuration setting not available
+ */
+int rtnl_link_inet6_get_flags(struct rtnl_link *link, uint32_t* out_flags)
+{
+ struct inet6_data *id = NULL;
+
+ if (!(id = rtnl_link_af_data(link, &inet6_ops)))
+ return -NLE_NOATTR;
+
+ *out_flags = id->i6_flags;
+ return 0;
+}
+
+/**
+ * Set IPv6 specific flags
+ * @arg link Link object
+ * @arg flags Flags to set
+ *
+ * Sets the link's IPv6 specific flags. Overwrites currently set flags.
+ *
+ * @return 0 on success
+ * @return -NLE_NOMEM could not allocate inet6 data
+ */
+int rtnl_link_inet6_set_flags(struct rtnl_link *link, uint32_t flags)
+{
+ struct inet6_data *id;
+
+ if (!(id = rtnl_link_af_alloc(link, &inet6_ops)))
+ return -NLE_NOMEM;
+
+ id->i6_flags = flags;
+ return 0;
+}
+
+/**
+ * Get IPv6 tokenized interface identifier
+ * @arg link Link object
+ * @arg token Tokenized interface identifier on success
+ *
+ * Returns the link's IPv6 tokenized interface identifier.
+ *
+ * @return 0 on success
+ * @return -NLE_NOMEM failure to allocate struct nl_addr result
+ * @return -NLE_NOATTR configuration setting not available
+ * @return -NLE_NOADDR tokenized interface identifier is not set
+ */
+int rtnl_link_inet6_get_token(struct rtnl_link *link, struct nl_addr **addr)
+{
+ struct inet6_data *id;
+
+ if (!(id = rtnl_link_af_data(link, &inet6_ops)))
+ return -NLE_NOATTR;
+
+ *addr = nl_addr_build(AF_INET6, &id->i6_token, sizeof(id->i6_token));
+ if (!*addr)
+ return -NLE_NOMEM;
+ if (nl_addr_iszero(*addr)) {
+ nl_addr_put(*addr);
+ *addr = NULL;
+ return -NLE_NOADDR;
+ }
+
+ return 0;
+}
+
+/**
+ * Set IPv6 tokenized interface identifier
+ * @arg link Link object
+ * @arg token Tokenized interface identifier
+ *
+ * Sets the link's IPv6 tokenized interface identifier.
+ *
+ * @return 0 on success
+ * @return -NLE_NOMEM could not allocate inet6 data
+ * @return -NLE_INVAL addr is not a valid inet6 address
+ */
+int rtnl_link_inet6_set_token(struct rtnl_link *link, struct nl_addr *addr)
+{
+ struct inet6_data *id;
+
+ if ((nl_addr_get_family(addr) != AF_INET6) ||
+ (nl_addr_get_len(addr) != sizeof(id->i6_token)))
+ return -NLE_INVAL;
+
+ if (!(id = rtnl_link_af_alloc(link, &inet6_ops)))
+ return -NLE_NOMEM;
+
+ memcpy(&id->i6_token, nl_addr_get_binary_addr(addr),
+ sizeof(id->i6_token));
+ return 0;
+}
+
+/**
+ * Get IPv6 link-local address generation mode
+ * @arg link Link object
+ * @arg mode Generation mode on success
+ *
+ * Returns the link's IPv6 link-local address generation mode.
+ *
+ * @return 0 on success
+ * @return -NLE_NOATTR configuration setting not available
+ * @return -NLE_INVAL generation mode unknown. If the link was received via
+ * netlink, it means that address generation mode is not
+ * supported by the kernel.
+ */
+int rtnl_link_inet6_get_addr_gen_mode(struct rtnl_link *link, uint8_t *mode)
+{
+ struct inet6_data *id;
+
+ if (!(id = rtnl_link_af_data(link, &inet6_ops)))
+ return -NLE_NOATTR;
+
+ if (id->i6_addr_gen_mode == I6_ADDR_GEN_MODE_UNKNOWN)
+ return -NLE_INVAL;
+
+ *mode = id->i6_addr_gen_mode;
+ return 0;
+}
+
+/**
+ * Set IPv6 link-local address generation mode
+ * @arg link Link object
+ * @arg mode Generation mode
+ *
+ * Sets the link's IPv6 link-local address generation mode.
+ *
+ * @return 0 on success
+ * @return -NLE_NOMEM could not allocate inet6 data
+ */
+int rtnl_link_inet6_set_addr_gen_mode(struct rtnl_link *link, uint8_t mode)
+{
+ struct inet6_data *id;
+
+ if (!(id = rtnl_link_af_alloc(link, &inet6_ops)))
+ return -NLE_NOMEM;
+
+ id->i6_addr_gen_mode = mode;
+ return 0;
+}
+
static void __init inet6_init(void)
{
rtnl_link_af_register(&inet6_ops);
diff --git a/lib/route/link/ip6tnl.c b/lib/route/link/ip6tnl.c
index 9fe13674..085bf66f 100644
--- a/lib/route/link/ip6tnl.c
+++ b/lib/route/link/ip6tnl.c
@@ -28,6 +28,7 @@
#include <netlink/utils.h>
#include <netlink/object.h>
#include <netlink/route/rtnl.h>
+#include <netlink/route/link/ip6tnl.h>
#include <netlink-private/route/link/api.h>
#include <linux/if_tunnel.h>
#include <netinet/in.h>
@@ -72,11 +73,15 @@ static int ip6_tnl_alloc(struct rtnl_link *link)
{
struct ip6_tnl_info *ip6_tnl;
- ip6_tnl = calloc(1, sizeof(*ip6_tnl));
- if (!ip6_tnl)
- return -NLE_NOMEM;
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*ip6_tnl));
+ else {
+ ip6_tnl = calloc(1, sizeof(*ip6_tnl));
+ if (!ip6_tnl)
+ return -NLE_NOMEM;
- link->l_info = ip6_tnl;
+ link->l_info = ip6_tnl;
+ }
return 0;
}
@@ -88,7 +93,7 @@ static int ip6_tnl_parse(struct rtnl_link *link, struct nlattr *data,
struct ip6_tnl_info *ip6_tnl;
int err;
- NL_DBG(3, "Parsing IP6_TNL link info");
+ NL_DBG(3, "Parsing IP6_TNL link info\n");
err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, ip6_tnl_policy);
if (err < 0)
@@ -213,10 +218,16 @@ static void ip6_tnl_dump_details(struct rtnl_link *link, struct nl_dump_params *
{
struct ip6_tnl_info *ip6_tnl = link->l_info;
char *name, addr[INET6_ADDRSTRLEN];
+ struct rtnl_link *parent;
if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LINK) {
nl_dump(p, " link ");
- name = rtnl_link_get_name(link);
+
+ name = NULL;
+ parent = link_lookup(link->ce_cache, ip6_tnl->link);
+ if (parent)
+ name = rtnl_link_get_name(parent);
+
if (name)
nl_dump_line(p, "%s\n", name);
else
diff --git a/lib/route/link/ipgre.c b/lib/route/link/ipgre.c
index 74dbb9d3..a7665fef 100644
--- a/lib/route/link/ipgre.c
+++ b/lib/route/link/ipgre.c
@@ -28,6 +28,7 @@
#include <netlink/utils.h>
#include <netlink/object.h>
#include <netlink/route/rtnl.h>
+#include <netlink/route/link/ipgre.h>
#include <netlink-private/route/link/api.h>
#include <linux/if_tunnel.h>
@@ -74,11 +75,15 @@ static int ipgre_alloc(struct rtnl_link *link)
{
struct ipgre_info *ipgre;
- ipgre = calloc(1, sizeof(*ipgre));
- if (!ipgre)
- return -NLE_NOMEM;
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*ipgre));
+ else {
+ ipgre = calloc(1, sizeof(*ipgre));
+ if (!ipgre)
+ return -NLE_NOMEM;
- link->l_info = ipgre;
+ link->l_info = ipgre;
+ }
return 0;
}
@@ -86,11 +91,11 @@ static int ipgre_alloc(struct rtnl_link *link)
static int ipgre_parse(struct rtnl_link *link, struct nlattr *data,
struct nlattr *xstats)
{
- struct nlattr *tb[IFLA_IPTUN_MAX + 1];
+ struct nlattr *tb[IFLA_GRE_MAX + 1];
struct ipgre_info *ipgre;
int err;
- NL_DBG(3, "Parsing IPGRE link info");
+ NL_DBG(3, "Parsing IPGRE link info\n");
err = nla_parse_nested(tb, IFLA_GRE_MAX, data, ipgre_policy);
if (err < 0)
@@ -132,8 +137,8 @@ static int ipgre_parse(struct rtnl_link *link, struct nlattr *data,
ipgre->ipgre_mask |= IPGRE_ATTR_LOCAL;
}
- if (tb[IFLA_GRE_LOCAL]) {
- ipgre->remote = nla_get_u32(tb[IFLA_GRE_LOCAL]);
+ if (tb[IFLA_GRE_REMOTE]) {
+ ipgre->remote = nla_get_u32(tb[IFLA_GRE_REMOTE]);
ipgre->ipgre_mask |= IPGRE_ATTR_REMOTE;
}
@@ -154,7 +159,7 @@ static int ipgre_parse(struct rtnl_link *link, struct nlattr *data,
err = 0;
- errout:
+errout:
return err;
}
@@ -199,7 +204,7 @@ static int ipgre_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
nla_nest_end(msg, data);
- nla_put_failure:
+nla_put_failure:
return 0;
}
@@ -221,10 +226,16 @@ static void ipgre_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
{
struct ipgre_info *ipgre = link->l_info;
char *name, addr[INET_ADDRSTRLEN];
+ struct rtnl_link *parent;
if (ipgre->ipgre_mask & IPGRE_ATTR_LINK) {
nl_dump(p, " link ");
- name = rtnl_link_get_name(link);
+
+ name = NULL;
+ parent = link_lookup(link->ce_cache, ipgre->link);
+ if (parent)
+ name = rtnl_link_get_name(parent);
+
if (name)
nl_dump_line(p, "%s\n", name);
else
@@ -304,6 +315,27 @@ static int ipgre_clone(struct rtnl_link *dst, struct rtnl_link *src)
return 0;
}
+static int ipgretap_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+ struct ipgre_info *ipgre_dst, *ipgre_src = src->l_info;
+ int err;
+
+ dst->l_info = NULL;
+
+ err = rtnl_link_set_type(dst, "gretap");
+ if (err < 0)
+ return err;
+
+ ipgre_dst = dst->l_info;
+
+ if (!ipgre_dst || !ipgre_src)
+ BUG();
+
+ memcpy(ipgre_dst, ipgre_src, sizeof(struct ipgre_info));
+
+ return 0;
+}
+
static struct rtnl_link_info_ops ipgre_info_ops = {
.io_name = "gre",
.io_alloc = ipgre_alloc,
@@ -317,10 +349,24 @@ static struct rtnl_link_info_ops ipgre_info_ops = {
.io_free = ipgre_free,
};
-#define IS_IPGRE_LINK_ASSERT(link) \
- if ((link)->l_info_ops != &ipgre_info_ops) { \
- APPBUG("Link is not a ipgre link. set type \"gre\" first.");\
- return -NLE_OPNOTSUPP; \
+static struct rtnl_link_info_ops ipgretap_info_ops = {
+ .io_name = "gretap",
+ .io_alloc = ipgre_alloc,
+ .io_parse = ipgre_parse,
+ .io_dump = {
+ [NL_DUMP_LINE] = ipgre_dump_line,
+ [NL_DUMP_DETAILS] = ipgre_dump_details,
+ },
+ .io_clone = ipgretap_clone,
+ .io_put_attrs = ipgre_put_attrs,
+ .io_free = ipgre_free,
+};
+
+#define IS_IPGRE_LINK_ASSERT(link) \
+ if ((link)->l_info_ops != &ipgre_info_ops && \
+ (link)->l_info_ops != &ipgretap_info_ops) { \
+ APPBUG("Link is not a ipgre link. set type \"gre/gretap\" first.");\
+ return -NLE_OPNOTSUPP; \
}
struct rtnl_link *rtnl_link_ipgre_alloc(void)
@@ -351,8 +397,9 @@ int rtnl_link_is_ipgre(struct rtnl_link *link)
{
return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "gre");
}
+
/**
- * Create a new ipip tunnel device
+ * Create a new IPGRE tunnel device
* @arg sock netlink socket
* @arg name name of the tunnel deviceL
*
@@ -376,6 +423,61 @@ int rtnl_link_ipgre_add(struct nl_sock *sk, const char *name)
return err;
}
+
+struct rtnl_link *rtnl_link_ipgretap_alloc(void)
+{
+ struct rtnl_link *link;
+ int err;
+
+ link = rtnl_link_alloc();
+ if (!link)
+ return NULL;
+
+ err = rtnl_link_set_type(link, "gretap");
+ if (err < 0) {
+ rtnl_link_put(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/**
+ * Check if link is a IPGRETAP link
+ * @arg link Link object
+ *
+ * @return True if link is a IPGRETAP link, otherwise 0 is returned.
+ */
+int rtnl_link_is_ipgretap(struct rtnl_link *link)
+{
+ return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "gretap");
+}
+/**
+ * Create a new IPGRETAP tunnel device
+ * @arg sock netlink socket
+ * @arg name name of the tunnel deviceL
+ *
+ * Creates a new IPGRETAP tunnel device in the kernel
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ipgretap_add(struct nl_sock *sk, const char *name)
+{
+ struct rtnl_link *link;
+ int err;
+
+ link = rtnl_link_ipgretap_alloc();
+ if (!link)
+ return -NLE_NOMEM;
+
+ if(name)
+ rtnl_link_set_name(link, name);
+
+ err = rtnl_link_add(sk, link, NLM_F_CREATE);
+ rtnl_link_put(link);
+
+ return err;
+}
+
/**
* Set IPGRE tunnel interface index
* @arg link Link object
@@ -707,7 +809,7 @@ int rtnl_link_ipgre_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc)
*
* @return pmtudisc value
*/
-uint8_t rtnl_link_get_pmtudisc(struct rtnl_link *link)
+uint8_t rtnl_link_ipgre_get_pmtudisc(struct rtnl_link *link)
{
struct ipgre_info *ipgre = link->l_info;
@@ -716,12 +818,25 @@ uint8_t rtnl_link_get_pmtudisc(struct rtnl_link *link)
return ipgre->pmtudisc;
}
+/* Function prototype for ABI-preserving wrapper (not in public header) to avoid
+ * GCC warning about missing prototype. */
+uint8_t rtnl_link_get_pmtudisc(struct rtnl_link *link);
+
+uint8_t rtnl_link_get_pmtudisc(struct rtnl_link *link)
+{
+ /* rtnl_link_ipgre_get_pmtudisc() was wrongly named. Keep this
+ * to preserve ABI. */
+ return rtnl_link_ipgre_get_pmtudisc (link);
+}
+
static void __init ipgre_init(void)
{
rtnl_link_register_info(&ipgre_info_ops);
+ rtnl_link_register_info(&ipgretap_info_ops);
}
static void __exit ipgre_exit(void)
{
rtnl_link_unregister_info(&ipgre_info_ops);
+ rtnl_link_unregister_info(&ipgretap_info_ops);
}
diff --git a/lib/route/link/ipip.c b/lib/route/link/ipip.c
index ecf86ad7..3243b56b 100644
--- a/lib/route/link/ipip.c
+++ b/lib/route/link/ipip.c
@@ -28,6 +28,7 @@
#include <netlink/utils.h>
#include <netlink/object.h>
#include <netlink/route/rtnl.h>
+#include <netlink/route/link/ipip.h>
#include <netlink-private/route/link/api.h>
#include <linux/if_tunnel.h>
@@ -62,11 +63,15 @@ static int ipip_alloc(struct rtnl_link *link)
{
struct ipip_info *ipip;
- ipip = calloc(1, sizeof(*ipip));
- if (!ipip)
- return -NLE_NOMEM;
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*ipip));
+ else {
+ ipip = calloc(1, sizeof(*ipip));
+ if (!ipip)
+ return -NLE_NOMEM;
- link->l_info = ipip;
+ link->l_info = ipip;
+ }
return 0;
}
@@ -78,7 +83,7 @@ static int ipip_parse(struct rtnl_link *link, struct nlattr *data,
struct ipip_info *ipip;
int err;
- NL_DBG(3, "Parsing IPIP link info");
+ NL_DBG(3, "Parsing IPIP link info\n");
err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, ipip_policy);
if (err < 0)
@@ -176,10 +181,16 @@ static void ipip_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
{
struct ipip_info *ipip = link->l_info;
char *name, addr[INET_ADDRSTRLEN];
+ struct rtnl_link *parent;
if (ipip->ipip_mask & IPIP_ATTR_LINK) {
nl_dump(p, " link ");
- name = rtnl_link_get_name(link);
+
+ name = NULL;
+ parent = link_lookup(link->ce_cache, ipip->link);
+ if (parent)
+ name = rtnl_link_get_name(parent);
+
if (name)
nl_dump_line(p, "%s\n", name);
else
diff --git a/lib/route/link/ipvlan.c b/lib/route/link/ipvlan.c
new file mode 100644
index 00000000..84ace435
--- /dev/null
+++ b/lib/route/link/ipvlan.c
@@ -0,0 +1,277 @@
+/*
+ * lib/route/link/ipvlan.c IPVLAN Link Info
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2015 Cong Wang <cwang@twopensource.com>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup ipvlan IPVLAN
+ * IP-based Virtual LAN link module
+ *
+ * @details
+ * \b Link Type Name: "ipvlan"
+ *
+ * @route_doc{link_ipvlan, IPVLAN Documentation}
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink-private/route/link/api.h>
+#include <netlink/route/link/ipvlan.h>
+
+#include <linux/if_link.h>
+
+/** @cond SKIP */
+#define IPVLAN_HAS_MODE (1<<0)
+
+struct ipvlan_info
+{
+ uint16_t ipi_mode;
+ uint32_t ipi_mask;
+};
+
+/** @endcond */
+
+static struct nla_policy ipvlan_policy[IFLA_IPVLAN_MAX+1] = {
+ [IFLA_IPVLAN_MODE] = { .type = NLA_U16 },
+};
+
+static int ipvlan_alloc(struct rtnl_link *link)
+{
+ struct ipvlan_info *ipi;
+
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*ipi));
+ else {
+ if ((ipi = calloc(1, sizeof(*ipi))) == NULL)
+ return -NLE_NOMEM;
+
+ link->l_info = ipi;
+ }
+
+ return 0;
+}
+
+static int ipvlan_parse(struct rtnl_link *link, struct nlattr *data,
+ struct nlattr *xstats)
+{
+ struct nlattr *tb[IFLA_IPVLAN_MAX+1];
+ struct ipvlan_info *ipi;
+ int err;
+
+ NL_DBG(3, "Parsing IPVLAN link info\n");
+
+ if ((err = nla_parse_nested(tb, IFLA_IPVLAN_MAX, data, ipvlan_policy)) < 0)
+ goto errout;
+
+ if ((err = ipvlan_alloc(link)) < 0)
+ goto errout;
+
+ ipi = link->l_info;
+
+ if (tb[IFLA_IPVLAN_MODE]) {
+ ipi->ipi_mode = nla_get_u16(tb[IFLA_IPVLAN_MODE]);
+ ipi->ipi_mask |= IPVLAN_HAS_MODE;
+ }
+
+ err = 0;
+errout:
+ return err;
+}
+
+static void ipvlan_free(struct rtnl_link *link)
+{
+ free(link->l_info);
+ link->l_info = NULL;
+}
+
+static void ipvlan_dump(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ char buf[64];
+ struct ipvlan_info *ipi = link->l_info;
+
+ if (ipi->ipi_mask & IPVLAN_HAS_MODE) {
+ rtnl_link_ipvlan_mode2str(ipi->ipi_mode, buf, sizeof(buf));
+ nl_dump(p, "ipvlan-mode %s", buf);
+ }
+}
+
+static int ipvlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+ struct ipvlan_info *vdst, *vsrc = src->l_info;
+ int err;
+
+ dst->l_info = NULL;
+ if ((err = rtnl_link_set_type(dst, "ipvlan")) < 0)
+ return err;
+ vdst = dst->l_info;
+
+ if (!vdst || !vsrc)
+ return -NLE_NOMEM;
+
+ memcpy(vdst, vsrc, sizeof(struct ipvlan_info));
+
+ return 0;
+}
+
+static int ipvlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+ struct ipvlan_info *ipi = link->l_info;
+ struct nlattr *data;
+
+ if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+ return -NLE_MSGSIZE;
+
+ if (ipi->ipi_mask & IPVLAN_HAS_MODE)
+ NLA_PUT_U16(msg, IFLA_IPVLAN_MODE, ipi->ipi_mode);
+
+ nla_nest_end(msg, data);
+
+nla_put_failure:
+
+ return 0;
+}
+
+static struct rtnl_link_info_ops ipvlan_info_ops = {
+ .io_name = "ipvlan",
+ .io_alloc = ipvlan_alloc,
+ .io_parse = ipvlan_parse,
+ .io_dump = {
+ [NL_DUMP_LINE] = ipvlan_dump,
+ [NL_DUMP_DETAILS] = ipvlan_dump,
+ },
+ .io_clone = ipvlan_clone,
+ .io_put_attrs = ipvlan_put_attrs,
+ .io_free = ipvlan_free,
+};
+
+/** @cond SKIP */
+#define IS_IPVLAN_LINK_ASSERT(link) \
+ if ((link)->l_info_ops != &ipvlan_info_ops) { \
+ APPBUG("Link is not a ipvlan link. set type \"ipvlan\" first."); \
+ return -NLE_OPNOTSUPP; \
+ }
+/** @endcond */
+
+/**
+ * @name IPVLAN Object
+ * @{
+ */
+
+/**
+ * Allocate link object of type IPVLAN
+ *
+ * @return Allocated link object or NULL.
+ */
+struct rtnl_link *rtnl_link_ipvlan_alloc(void)
+{
+ struct rtnl_link *link;
+ int err;
+
+ if (!(link = rtnl_link_alloc()))
+ return NULL;
+
+ if ((err = rtnl_link_set_type(link, "ipvlan")) < 0) {
+ rtnl_link_put(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/**
+ * Check if link is a IPVLAN link
+ * @arg link Link object
+ *
+ * @return True if link is a IPVLAN link, otherwise false is returned.
+ */
+int rtnl_link_is_ipvlan(struct rtnl_link *link)
+{
+ return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "ipvlan");
+}
+
+/**
+ * Set IPVLAN MODE
+ * @arg link Link object
+ * @arg mode IPVLAN mode
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_ipvlan_set_mode(struct rtnl_link *link, uint16_t mode)
+{
+ struct ipvlan_info *ipi = link->l_info;
+
+ IS_IPVLAN_LINK_ASSERT(link);
+
+ ipi->ipi_mode = mode;
+ ipi->ipi_mask |= IPVLAN_HAS_MODE;
+
+ return 0;
+}
+
+/**
+ * Get IPVLAN Mode
+ * @arg link Link object
+ * @arg out_mode on success, return the mode
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_ipvlan_get_mode(struct rtnl_link *link, uint16_t *out_mode)
+{
+ struct ipvlan_info *ipi = link->l_info;
+
+ IS_IPVLAN_LINK_ASSERT(link);
+
+ if (!(ipi->ipi_mask & IPVLAN_HAS_MODE))
+ return -NLE_INVAL;
+ *out_mode = ipi->ipi_mode;
+ return 0;
+}
+
+/** @} */
+
+static const struct trans_tbl ipvlan_modes[] = {
+ __ADD(IPVLAN_MODE_L2, l2),
+ __ADD(IPVLAN_MODE_L3, l3),
+};
+
+/**
+ * @name Mode Translation
+ * @{
+ */
+
+char *rtnl_link_ipvlan_mode2str(int mode, char *buf, size_t len)
+{
+ return __type2str(mode, buf, len, ipvlan_modes, ARRAY_SIZE(ipvlan_modes));
+}
+
+int rtnl_link_ipvlan_str2mode(const char *name)
+{
+ return __str2type(name, ipvlan_modes, ARRAY_SIZE(ipvlan_modes));
+}
+
+/** @} */
+
+static void __init ipvlan_init(void)
+{
+ rtnl_link_register_info(&ipvlan_info_ops);
+}
+
+static void __exit ipvlan_exit(void)
+{
+ rtnl_link_unregister_info(&ipvlan_info_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/ipvti.c b/lib/route/link/ipvti.c
index 71f61c36..851d5665 100644
--- a/lib/route/link/ipvti.c
+++ b/lib/route/link/ipvti.c
@@ -1,4 +1,4 @@
- /*
+/*
* lib/route/link/ipvti.c IPVTI Link Info
*
* This library is free software; you can redistribute it and/or
@@ -28,6 +28,7 @@
#include <netlink/utils.h>
#include <netlink/object.h>
#include <netlink/route/rtnl.h>
+#include <netlink/route/link/ipvti.h>
#include <netlink-private/route/link/api.h>
#include <linux/if_tunnel.h>
@@ -47,7 +48,7 @@ struct ipvti_info
uint32_t ipvti_mask;
};
-static struct nla_policy ipvti_policy[IFLA_GRE_MAX + 1] = {
+static struct nla_policy ipvti_policy[IFLA_VTI_MAX + 1] = {
[IFLA_VTI_LINK] = { .type = NLA_U32 },
[IFLA_VTI_IKEY] = { .type = NLA_U32 },
[IFLA_VTI_OKEY] = { .type = NLA_U32 },
@@ -59,11 +60,15 @@ static int ipvti_alloc(struct rtnl_link *link)
{
struct ipvti_info *ipvti;
- ipvti = calloc(1, sizeof(*ipvti));
- if (!ipvti)
- return -NLE_NOMEM;
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*ipvti));
+ else {
+ ipvti = calloc(1, sizeof(*ipvti));
+ if (!ipvti)
+ return -NLE_NOMEM;
- link->l_info = ipvti;
+ link->l_info = ipvti;
+ }
return 0;
}
@@ -71,13 +76,13 @@ static int ipvti_alloc(struct rtnl_link *link)
static int ipvti_parse(struct rtnl_link *link, struct nlattr *data,
struct nlattr *xstats)
{
- struct nlattr *tb[IFLA_IPTUN_MAX + 1];
+ struct nlattr *tb[IFLA_VTI_MAX + 1];
struct ipvti_info *ipvti;
int err;
- NL_DBG(3, "Parsing IPVTI link info");
+ NL_DBG(3, "Parsing IPVTI link info\n");
- err = nla_parse_nested(tb, IFLA_GRE_MAX, data, ipvti_policy);
+ err = nla_parse_nested(tb, IFLA_VTI_MAX, data, ipvti_policy);
if (err < 0)
goto errout;
@@ -114,7 +119,7 @@ static int ipvti_parse(struct rtnl_link *link, struct nlattr *data,
err = 0;
- errout:
+errout:
return err;
}
@@ -166,10 +171,16 @@ static void ipvti_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
{
struct ipvti_info *ipvti = link->l_info;
char *name, addr[INET_ADDRSTRLEN];
+ struct rtnl_link *parent;
if (ipvti->ipvti_mask & IPVTI_ATTR_LINK) {
nl_dump(p, " link ");
- name = rtnl_link_get_name(link);
+
+ name = NULL;
+ parent = link_lookup(link->ce_cache, ipvti->link);
+ if (parent)
+ name = rtnl_link_get_name(parent);
+
if (name)
nl_dump_line(p, "%s\n", name);
else
diff --git a/lib/route/link/macsec.c b/lib/route/link/macsec.c
new file mode 100644
index 00000000..fa115e27
--- /dev/null
+++ b/lib/route/link/macsec.c
@@ -0,0 +1,850 @@
+/*
+ * lib/route/link/macsec.c MACsec Link Info
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2016 Sabrina Dubroca <sd@queasysnail.net>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup macsec MACsec
+ * MACsec link module
+ *
+ * @details
+ * \b Link Type Name: "macsec"
+ *
+ * @route_doc{link_macsec, MACsec Documentation}
+ *
+ * @{
+ */
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link/macsec.h>
+#include <netlink-private/route/link/api.h>
+#include <netlink-private/utils.h>
+
+#include <linux/if_macsec.h>
+
+/** @cond SKIP */
+#define MACSEC_ATTR_SCI (1 << 0)
+#define MACSEC_ATTR_ICV_LEN (1 << 1)
+#define MACSEC_ATTR_CIPHER_SUITE (1 << 2)
+#define MACSEC_ATTR_WINDOW (1 << 3)
+#define MACSEC_ATTR_ENCODING_SA (1 << 4)
+#define MACSEC_ATTR_ENCRYPT (1 << 5)
+#define MACSEC_ATTR_PROTECT (1 << 6)
+#define MACSEC_ATTR_INC_SCI (1 << 7)
+#define MACSEC_ATTR_ES (1 << 8)
+#define MACSEC_ATTR_SCB (1 << 9)
+#define MACSEC_ATTR_REPLAY_PROTECT (1 << 10)
+#define MACSEC_ATTR_VALIDATION (1 << 11)
+#define MACSEC_ATTR_PORT (1 << 12)
+
+struct macsec_info {
+ int ifindex;
+ uint64_t sci;
+ uint16_t port;
+ uint64_t cipher_suite;
+ uint16_t icv_len;
+ uint32_t window;
+ enum macsec_validation_type validate;
+ uint8_t encoding_sa;
+
+ uint8_t send_sci, end_station, scb, replay_protect, protect, encrypt;
+
+ uint32_t ce_mask;
+};
+
+#define DEFAULT_ICV_LEN 16
+
+/** @endcond */
+
+static struct nla_policy macsec_policy[IFLA_MACSEC_MAX+1] = {
+ [IFLA_MACSEC_SCI] = { .type = NLA_U64 },
+ [IFLA_MACSEC_ICV_LEN] = { .type = NLA_U8 },
+ [IFLA_MACSEC_CIPHER_SUITE] = { .type = NLA_U64 },
+ [IFLA_MACSEC_WINDOW] = { .type = NLA_U32 },
+ [IFLA_MACSEC_ENCODING_SA] = { .type = NLA_U8 },
+ [IFLA_MACSEC_ENCRYPT] = { .type = NLA_U8 },
+ [IFLA_MACSEC_PROTECT] = { .type = NLA_U8 },
+ [IFLA_MACSEC_INC_SCI] = { .type = NLA_U8 },
+ [IFLA_MACSEC_ES] = { .type = NLA_U8 },
+ [IFLA_MACSEC_SCB] = { .type = NLA_U8 },
+ [IFLA_MACSEC_REPLAY_PROTECT] = { .type = NLA_U8 },
+ [IFLA_MACSEC_VALIDATION] = { .type = NLA_U8 },
+};
+
+/**
+ * @name MACsec Object
+ * @{
+ */
+
+/**
+ * Allocate link object of type MACsec
+ *
+ * @return Allocated link object or NULL.
+ */
+static int macsec_alloc(struct rtnl_link *link)
+{
+ struct macsec_info *info;
+
+ if (!link->l_info) {
+ link->l_info = malloc(sizeof(struct macsec_info));
+ if (!link->l_info)
+ return -NLE_NOMEM;
+ }
+
+ memset(link->l_info, 0, sizeof(struct macsec_info));
+ info = link->l_info;
+
+ info->cipher_suite = MACSEC_DEFAULT_CIPHER_ID;
+ info->icv_len = DEFAULT_ICV_LEN;
+ info->ce_mask = MACSEC_ATTR_CIPHER_SUITE | MACSEC_ATTR_ICV_LEN;
+
+ return 0;
+}
+
+static int macsec_parse(struct rtnl_link *link, struct nlattr *data,
+ struct nlattr *xstats)
+{
+ struct nlattr *tb[IFLA_MACSEC_MAX+1];
+ struct macsec_info *info;
+ int err;
+
+ NL_DBG(3, "Parsing MACsec link info\n");
+
+ if ((err = nla_parse_nested(tb, IFLA_MACSEC_MAX, data, macsec_policy)) < 0)
+ goto errout;
+
+ if ((err = macsec_alloc(link)) < 0)
+ goto errout;
+
+ info = link->l_info;
+
+ if (tb[IFLA_MACSEC_SCI]) {
+ info->sci = nla_get_u64(tb[IFLA_MACSEC_SCI]);
+ info->ce_mask |= MACSEC_ATTR_SCI;
+ }
+
+ if (tb[IFLA_MACSEC_PROTECT]) {
+ info->protect = nla_get_u8(tb[IFLA_MACSEC_PROTECT]);
+ info->ce_mask |= MACSEC_ATTR_PROTECT;
+ }
+
+ if (tb[IFLA_MACSEC_CIPHER_SUITE]) {
+ info->cipher_suite = nla_get_u64(tb[IFLA_MACSEC_CIPHER_SUITE]);
+ info->ce_mask |= MACSEC_ATTR_CIPHER_SUITE;
+ }
+
+ if (tb[IFLA_MACSEC_ICV_LEN]) {
+ info->icv_len = nla_get_u8(tb[IFLA_MACSEC_ICV_LEN]);
+ info->ce_mask |= MACSEC_ATTR_ICV_LEN;
+ }
+
+ if (tb[IFLA_MACSEC_ENCODING_SA]) {
+ info->encoding_sa = nla_get_u8(tb[IFLA_MACSEC_ENCODING_SA]);
+ info->ce_mask |= MACSEC_ATTR_ENCODING_SA;
+ }
+
+ if (tb[IFLA_MACSEC_VALIDATION]) {
+ info->validate = nla_get_u8(tb[IFLA_MACSEC_VALIDATION]);
+ info->ce_mask |= MACSEC_ATTR_VALIDATION;
+ }
+
+ if (tb[IFLA_MACSEC_ENCRYPT]) {
+ info->encrypt = nla_get_u8(tb[IFLA_MACSEC_ENCRYPT]);
+ info->ce_mask |= MACSEC_ATTR_ENCRYPT;
+ }
+
+ if (tb[IFLA_MACSEC_INC_SCI]) {
+ info->send_sci = nla_get_u8(tb[IFLA_MACSEC_INC_SCI]);
+ info->ce_mask |= MACSEC_ATTR_INC_SCI;
+ }
+
+ if (tb[IFLA_MACSEC_ES]) {
+ info->end_station = nla_get_u8(tb[IFLA_MACSEC_ES]);
+ info->ce_mask |= MACSEC_ATTR_ES;
+ }
+
+ if (tb[IFLA_MACSEC_SCB]) {
+ info->scb = nla_get_u8(tb[IFLA_MACSEC_SCB]);
+ info->ce_mask |= MACSEC_ATTR_SCB;
+ }
+
+ if (tb[IFLA_MACSEC_REPLAY_PROTECT]) {
+ info->replay_protect = nla_get_u8(tb[IFLA_MACSEC_REPLAY_PROTECT]);
+ info->ce_mask |= MACSEC_ATTR_REPLAY_PROTECT;
+ }
+
+ if (tb[IFLA_MACSEC_WINDOW]) {
+ info->window = nla_get_u32(tb[IFLA_MACSEC_WINDOW]);
+ info->ce_mask |= MACSEC_ATTR_WINDOW;
+ }
+
+ err = 0;
+errout:
+ return err;
+}
+
+static void macsec_free(struct rtnl_link *link)
+{
+ free(link->l_info);
+ link->l_info = NULL;
+}
+
+static const char *values_on_off[] = { "off", "on" };
+
+static const char *VALIDATE_STR[] = {
+ [MACSEC_VALIDATE_DISABLED] = "disabled",
+ [MACSEC_VALIDATE_CHECK] = "check",
+ [MACSEC_VALIDATE_STRICT] = "strict",
+};
+
+static char *replay_protect_str(char *buf, uint8_t replay_protect, uint8_t window)
+{
+ if (replay_protect == 1) {
+ sprintf(buf, "replay_protect on window %d", window);
+ } else if (replay_protect == 0) {
+ sprintf(buf, "replay_protect off");
+ } else {
+ buf[0] = '\0';
+ }
+
+ return buf;
+}
+
+/** @cond SKIP */
+#define PRINT_FLAG(buf, i, field, c) ({ if (i->field == 1) *buf++ = c; })
+/** @endcond */
+static char *flags_str(char *buf, unsigned char len, struct macsec_info *info)
+{
+ char *tmp = buf;
+ memset(tmp, 0, len);
+
+ PRINT_FLAG(tmp, info, protect, 'P');
+ PRINT_FLAG(tmp, info, encrypt, 'E');
+ PRINT_FLAG(tmp, info, send_sci, 'S');
+ PRINT_FLAG(tmp, info, end_station, 'e');
+ PRINT_FLAG(tmp, info, scb, 's');
+ PRINT_FLAG(tmp, info, replay_protect, 'R');
+
+ *tmp++ = ' ';
+ *tmp++ = 'v';
+ switch (info->validate) {
+ case MACSEC_VALIDATE_DISABLED:
+ *tmp++ = 'd';
+ break;
+ case MACSEC_VALIDATE_CHECK:
+ *tmp++ = 'c';
+ break;
+ case MACSEC_VALIDATE_STRICT:
+ *tmp++ = 's';
+ break;
+ default:
+ break;
+ }
+
+ sprintf(tmp, " %d", info->encoding_sa);
+
+ return buf;
+}
+
+static void macsec_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ struct macsec_info *info = link->l_info;
+ char tmp[128];
+
+ nl_dump(p, "sci %016llx <%s>", ntohll(info->sci), flags_str(tmp, sizeof(tmp), info));
+}
+
+static void macsec_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ struct macsec_info *info = link->l_info;
+ char tmp[128];
+
+ nl_dump(p, " sci %016llx protect %s encoding_sa %d encrypt %s send_sci %s validate %s %s\n",
+ ntohll(info->sci), values_on_off[info->protect], info->encoding_sa, values_on_off[info->encrypt], values_on_off[info->send_sci],
+ VALIDATE_STR[info->validate],
+ replay_protect_str(tmp, info->replay_protect, info->window));
+ nl_dump(p, " cipher suite: %016llx, icv_len %d\n",
+ info->cipher_suite, info->icv_len);
+}
+
+static int macsec_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+ struct macsec_info *copy, *info = src->l_info;
+ int err;
+
+ dst->l_info = NULL;
+ if ((err = rtnl_link_set_type(dst, "macsec")) < 0)
+ return err;
+ copy = dst->l_info;
+
+ if (!info || !copy)
+ return -NLE_NOMEM;
+
+ memcpy(copy, info, sizeof(struct macsec_info));
+
+ return 0;
+}
+
+static int macsec_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+ struct macsec_info *info = link->l_info;
+ struct nlattr *data;
+
+ if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+ return -NLE_MSGSIZE;
+
+ if (info->ce_mask & MACSEC_ATTR_SCI)
+ NLA_PUT_U64(msg, IFLA_MACSEC_SCI, info->sci);
+ else if (info->ce_mask & MACSEC_ATTR_PORT)
+ NLA_PUT_U16(msg, IFLA_MACSEC_PORT, htons(info->port));
+
+ if ((info->ce_mask & MACSEC_ATTR_ENCRYPT))
+ NLA_PUT_U8(msg, IFLA_MACSEC_ENCRYPT, info->encrypt);
+
+ if (info->cipher_suite != MACSEC_DEFAULT_CIPHER_ID || info->icv_len != DEFAULT_ICV_LEN) {
+ NLA_PUT_U64(msg, IFLA_MACSEC_CIPHER_SUITE, info->cipher_suite);
+ NLA_PUT_U8(msg, IFLA_MACSEC_ICV_LEN, info->icv_len);
+ }
+
+ if ((info->ce_mask & MACSEC_ATTR_INC_SCI))
+ NLA_PUT_U8(msg, IFLA_MACSEC_INC_SCI, info->send_sci);
+
+ if ((info->ce_mask & MACSEC_ATTR_ES))
+ NLA_PUT_U8(msg, IFLA_MACSEC_ES, info->end_station);
+
+ if ((info->ce_mask & MACSEC_ATTR_SCB))
+ NLA_PUT_U8(msg, IFLA_MACSEC_SCB, info->scb);
+
+ if ((info->ce_mask & MACSEC_ATTR_PROTECT))
+ NLA_PUT_U8(msg, IFLA_MACSEC_PROTECT, info->protect);
+
+ if ((info->ce_mask & MACSEC_ATTR_REPLAY_PROTECT)) {
+ if (info->replay_protect && !(info->ce_mask & MACSEC_ATTR_WINDOW))
+ return -NLE_INVAL;
+
+ NLA_PUT_U8(msg, IFLA_MACSEC_REPLAY_PROTECT, info->replay_protect);
+ NLA_PUT_U32(msg, IFLA_MACSEC_WINDOW, info->window);
+ }
+
+ if ((info->ce_mask & MACSEC_ATTR_VALIDATION))
+ NLA_PUT_U8(msg, IFLA_MACSEC_VALIDATION, info->validate);
+
+ if ((info->ce_mask & MACSEC_ATTR_ENCODING_SA))
+ NLA_PUT_U8(msg, IFLA_MACSEC_ENCODING_SA, info->encoding_sa);
+
+ nla_nest_end(msg, data);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+static int macsec_compare(struct rtnl_link *link_a, struct rtnl_link *link_b,
+ int flags)
+{
+ struct macsec_info *a = link_a->l_info;
+ struct macsec_info *b = link_b->l_info;
+ int diff = 0;
+ uint32_t attrs = flags & LOOSE_COMPARISON ? b->ce_mask : ~0;
+
+#define MACSEC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, MACSEC_ATTR_##ATTR, a, b, EXPR)
+
+ if (a->ce_mask & MACSEC_ATTR_SCI && b->ce_mask & MACSEC_ATTR_SCI)
+ diff |= MACSEC_DIFF(SCI, a->sci != b->sci);
+ else if (a->ce_mask & MACSEC_ATTR_PORT && b->ce_mask & MACSEC_ATTR_PORT)
+ diff |= MACSEC_DIFF(PORT, a->port != b->port);
+
+ if (a->ce_mask & MACSEC_ATTR_CIPHER_SUITE && b->ce_mask & MACSEC_ATTR_CIPHER_SUITE) {
+ diff |= MACSEC_DIFF(ICV_LEN, a->icv_len != b->icv_len);
+ diff |= MACSEC_DIFF(CIPHER_SUITE, a->cipher_suite != b->cipher_suite);
+ }
+
+ if (a->ce_mask & MACSEC_ATTR_REPLAY_PROTECT && b->ce_mask & MACSEC_ATTR_REPLAY_PROTECT) {
+ int d = MACSEC_DIFF(REPLAY_PROTECT, a->replay_protect != b->replay_protect);
+ if (a->replay_protect && b->replay_protect)
+ d |= MACSEC_DIFF(WINDOW, a->window != b->window);
+ diff |= d;
+ }
+
+ diff |= MACSEC_DIFF(ENCODING_SA, a->encoding_sa != b->encoding_sa);
+ diff |= MACSEC_DIFF(ENCRYPT, a->encrypt != b->encrypt);
+ diff |= MACSEC_DIFF(PROTECT, a->protect != b->protect);
+ diff |= MACSEC_DIFF(INC_SCI, a->send_sci != b->send_sci);
+ diff |= MACSEC_DIFF(ES, a->end_station != b->end_station);
+ diff |= MACSEC_DIFF(SCB, a->scb != b->scb);
+ diff |= MACSEC_DIFF(VALIDATION, a->validate != b->validate);
+#undef MACSEC_DIFF
+
+ return diff;
+}
+
+
+static struct rtnl_link_info_ops macsec_info_ops = {
+ .io_name = "macsec",
+ .io_alloc = macsec_alloc,
+ .io_parse = macsec_parse,
+ .io_dump = {
+ [NL_DUMP_LINE] = macsec_dump_line,
+ [NL_DUMP_DETAILS] = macsec_dump_details,
+ },
+ .io_clone = macsec_clone,
+ .io_put_attrs = macsec_put_attrs,
+ .io_free = macsec_free,
+ .io_compare = macsec_compare,
+};
+
+static void __init macsec_init(void)
+{
+ rtnl_link_register_info(&macsec_info_ops);
+}
+
+static void __exit macsec_exit(void)
+{
+ rtnl_link_unregister_info(&macsec_info_ops);
+}
+
+/** @cond SKIP */
+#define IS_MACSEC_LINK_ASSERT(link) \
+ if ((link)->l_info_ops != &macsec_info_ops) { \
+ APPBUG("Link is not a MACsec link. set type \"macsec\" first."); \
+ return -NLE_OPNOTSUPP; \
+ }
+/** @endcond */
+
+struct rtnl_link *rtnl_link_macsec_alloc(void)
+{
+ struct rtnl_link *link = rtnl_link_alloc();
+
+ if (!link)
+ return NULL;
+
+ if (rtnl_link_set_type(link, "macsec") < 0) {
+ rtnl_link_put(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/**
+ * Set SCI
+ * @arg link Link object
+ * @arg sci Secure Channel Identifier in network byte order
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_macsec_set_sci(struct rtnl_link *link, uint64_t sci)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ info->sci = sci;
+ info->ce_mask |= MACSEC_ATTR_SCI;
+
+ return 0;
+}
+
+/**
+ * Get SCI
+ * @arg link Link object
+ * @arg sci On return points to the Secure Channel Identifier
+ * in network byte order
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_macsec_get_sci(struct rtnl_link *link, uint64_t *sci)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_SCI))
+ return -NLE_NOATTR;
+
+ if (sci)
+ *sci = info->sci;
+
+ return 0;
+}
+
+/**
+ * Set port identifier
+ * @arg link Link object
+ * @arg port Port identifier in host byte order
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_macsec_set_port(struct rtnl_link *link, uint16_t port)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ info->port = port;
+ info->ce_mask |= MACSEC_ATTR_PORT;
+
+ return 0;
+}
+
+/**
+ * Get port identifier
+ * @arg link Link object
+ * @arg port On return points to the port identifier in host byte order
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_macsec_get_port(struct rtnl_link *link, uint16_t *port)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_PORT))
+ return -NLE_NOATTR;
+
+ if (port)
+ *port = info->port;
+
+ return 0;
+}
+
+int rtnl_link_macsec_set_cipher_suite(struct rtnl_link *link, uint64_t cipher_suite)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ info->cipher_suite = cipher_suite;
+ info->ce_mask |= MACSEC_ATTR_CIPHER_SUITE;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_cipher_suite(struct rtnl_link *link, uint64_t *cs)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_CIPHER_SUITE))
+ return -NLE_NOATTR;
+
+ if (cs)
+ *cs = info->cipher_suite;
+
+ return 0;
+}
+
+int rtnl_link_macsec_set_icv_len(struct rtnl_link *link, uint16_t icv_len)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (icv_len > MACSEC_STD_ICV_LEN)
+ return -NLE_INVAL;
+
+ info->icv_len = icv_len;
+ info->ce_mask |= MACSEC_ATTR_ICV_LEN;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_icv_len(struct rtnl_link *link, uint16_t *icv_len)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_ICV_LEN))
+ return -NLE_NOATTR;
+
+ if (icv_len)
+ *icv_len = info->icv_len;
+
+ return 0;
+}
+
+int rtnl_link_macsec_set_protect(struct rtnl_link *link, uint8_t protect)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (protect > 1)
+ return -NLE_INVAL;
+
+ info->protect = protect;
+ info->ce_mask |= MACSEC_ATTR_PROTECT;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_protect(struct rtnl_link *link, uint8_t *protect)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_PROTECT))
+ return -NLE_NOATTR;
+
+ if (protect)
+ *protect = info->protect;
+
+ return 0;
+}
+
+int rtnl_link_macsec_set_encrypt(struct rtnl_link *link, uint8_t encrypt)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (encrypt > 1)
+ return -NLE_INVAL;
+
+ info->encrypt = encrypt;
+ info->ce_mask |= MACSEC_ATTR_ENCRYPT;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_encrypt(struct rtnl_link *link, uint8_t *encrypt)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_ENCRYPT))
+ return -NLE_NOATTR;
+
+ if (encrypt)
+ *encrypt = info->encrypt;
+
+ return 0;
+}
+
+int rtnl_link_macsec_set_encoding_sa(struct rtnl_link *link, uint8_t encoding_sa)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (encoding_sa > 3)
+ return -NLE_INVAL;
+
+ info->encoding_sa = encoding_sa;
+ info->ce_mask |= MACSEC_ATTR_ENCODING_SA;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_encoding_sa(struct rtnl_link *link, uint8_t *encoding_sa)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_ENCODING_SA))
+ return -NLE_NOATTR;
+
+ if (encoding_sa)
+ *encoding_sa = info->encoding_sa;
+
+ return 0;
+}
+
+int rtnl_link_macsec_set_validation_type(struct rtnl_link *link, enum macsec_validation_type validate)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (validate > 1)
+ return -NLE_INVAL;
+
+ info->validate = validate;
+ info->ce_mask |= MACSEC_ATTR_VALIDATION;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_validation_type(struct rtnl_link *link, enum macsec_validation_type *validate)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_VALIDATION))
+ return -NLE_NOATTR;
+
+ if (validate)
+ *validate = info->validate;
+
+ return 0;
+}
+
+int rtnl_link_macsec_set_replay_protect(struct rtnl_link *link, uint8_t replay_protect)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (replay_protect > 1)
+ return -NLE_INVAL;
+
+ info->replay_protect = replay_protect;
+ info->ce_mask |= MACSEC_ATTR_REPLAY_PROTECT;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_replay_protect(struct rtnl_link *link, uint8_t *replay_protect)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_REPLAY_PROTECT))
+ return -NLE_NOATTR;
+
+ if (replay_protect)
+ *replay_protect = info->replay_protect;
+
+ return 0;
+}
+
+int rtnl_link_macsec_set_window(struct rtnl_link *link, uint32_t window)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ info->window = window;
+ info->ce_mask |= MACSEC_ATTR_WINDOW;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_window(struct rtnl_link *link, uint32_t *window)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_WINDOW))
+ return -NLE_NOATTR;
+
+ if (window)
+ *window = info->window;
+
+ return 0;
+}
+
+int rtnl_link_macsec_set_send_sci(struct rtnl_link *link, uint8_t send_sci)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (send_sci > 1)
+ return -NLE_INVAL;
+
+ info->send_sci = send_sci;
+ info->ce_mask |= MACSEC_ATTR_INC_SCI;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_send_sci(struct rtnl_link *link, uint8_t *send_sci)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_INC_SCI))
+ return -NLE_NOATTR;
+
+ if (send_sci)
+ *send_sci = info->send_sci;
+
+ return 0;
+}
+
+int rtnl_link_macsec_set_end_station(struct rtnl_link *link, uint8_t end_station)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (end_station > 1)
+ return -NLE_INVAL;
+
+ info->end_station = end_station;
+ info->ce_mask |= MACSEC_ATTR_ES;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_end_station(struct rtnl_link *link, uint8_t *es)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_ES))
+ return -NLE_NOATTR;
+
+ if (es)
+ *es = info->end_station;
+
+ return 0;
+}
+
+int rtnl_link_macsec_set_scb(struct rtnl_link *link, uint8_t scb)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (scb > 1)
+ return -NLE_INVAL;
+
+ info->scb = scb;
+ info->ce_mask |= MACSEC_ATTR_SCB;
+
+ return 0;
+}
+
+int rtnl_link_macsec_get_scb(struct rtnl_link *link, uint8_t *scb)
+{
+ struct macsec_info *info = link->l_info;
+
+ IS_MACSEC_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & MACSEC_ATTR_SCB))
+ return -NLE_NOATTR;
+
+ if (scb)
+ *scb = info->scb;
+
+ return 0;
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/route/link/macvlan.c b/lib/route/link/macvlan.c
index 23409035..a23fe6d8 100644
--- a/lib/route/link/macvlan.c
+++ b/lib/route/link/macvlan.c
@@ -1,23 +1,24 @@
/*
- * lib/route/link/macvlan.c MACVLAN Link Info
+ * lib/route/link/macvlan.c MACVLAN Link Info
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation version 2.1
- * of the License.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
*
* Copyright (c) 2013 Michael Braun <michael-dev@fami-braun.de>
*/
/**
* @ingroup link
- * @defgroup macvlan MACVLAN
+ * @defgroup macvlan MACVLAN/MACVTAP
* MAC-based Virtual LAN link module
*
* @details
* \b Link Type Name: "macvlan"
*
* @route_doc{link_macvlan, MACVLAN Documentation}
+ * @route_doc{link_macvtap, MACVTAP Documentation}
*
* @{
*/
@@ -30,35 +31,54 @@
#include <netlink/route/rtnl.h>
#include <netlink-private/route/link/api.h>
#include <netlink/route/link/macvlan.h>
+#include <netlink/route/link/macvtap.h>
#include <linux/if_link.h>
/** @cond SKIP */
-#define MACVLAN_HAS_MODE (1<<0)
-#define MACVLAN_HAS_FLAGS (1<<1)
+#define MACVLAN_HAS_MODE (1<<0)
+#define MACVLAN_HAS_FLAGS (1<<1)
+#define MACVLAN_HAS_MACADDR (1<<2)
struct macvlan_info
{
- uint32_t mvi_mode;
- uint16_t mvi_flags; // there currently is only one flag and kernel has no flags_mask yet
- uint32_t mvi_mask;
+ uint32_t mvi_mode;
+ uint16_t mvi_flags; // there currently is only one flag and kernel has no flags_mask yet
+ uint32_t mvi_mask;
+ uint32_t mvi_maccount;
+ uint32_t mvi_macmode;
+ struct nl_addr **mvi_macaddr;
};
/** @endcond */
static struct nla_policy macvlan_policy[IFLA_MACVLAN_MAX+1] = {
- [IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
- [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
+ [IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
+ [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
+ [IFLA_MACVLAN_MACADDR_MODE] = { .type = NLA_U32 },
+ [IFLA_MACVLAN_MACADDR] = { .type = NLA_UNSPEC },
+ [IFLA_MACVLAN_MACADDR_DATA] = { .type = NLA_NESTED },
+ [IFLA_MACVLAN_MACADDR_COUNT] = { .type = NLA_U32 },
};
static int macvlan_alloc(struct rtnl_link *link)
{
struct macvlan_info *mvi;
-
- if ((mvi = calloc(1, sizeof(*mvi))) == NULL)
- return -NLE_NOMEM;
-
- link->l_info = mvi;
+ uint32_t i;
+
+ if (link->l_info) {
+ mvi = link->l_info;
+ for (i = 0; i < mvi->mvi_maccount; i++)
+ nl_addr_put(mvi->mvi_macaddr[i]);
+ free(mvi->mvi_macaddr);
+ memset(mvi, 0, sizeof(*mvi));
+ } else {
+ if ((mvi = calloc(1, sizeof(*mvi))) == NULL)
+ return -NLE_NOMEM;
+
+ link->l_info = mvi;
+ }
+ mvi->mvi_macmode = MACVLAN_MACADDR_SET;
return 0;
}
@@ -68,9 +88,11 @@ static int macvlan_parse(struct rtnl_link *link, struct nlattr *data,
{
struct nlattr *tb[IFLA_MACVLAN_MAX+1];
struct macvlan_info *mvi;
+ struct nlattr *nla;
+ int len;
int err;
- NL_DBG(3, "Parsing MACVLAN link info");
+ NL_DBG(3, "Parsing %s link info", link->l_info_ops->io_name);
if ((err = nla_parse_nested(tb, IFLA_MACVLAN_MAX, data, macvlan_policy)) < 0)
goto errout;
@@ -86,10 +108,36 @@ static int macvlan_parse(struct rtnl_link *link, struct nlattr *data,
}
if (tb[IFLA_MACVLAN_FLAGS]) {
- mvi->mvi_mode = nla_get_u16(tb[IFLA_MACVLAN_FLAGS]);
+ mvi->mvi_flags = nla_get_u16(tb[IFLA_MACVLAN_FLAGS]);
mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
}
+ if ( tb[IFLA_MACVLAN_MACADDR_COUNT]
+ && tb[IFLA_MACVLAN_MACADDR_DATA]) {
+ mvi->mvi_maccount = nla_get_u32(tb[IFLA_MACVLAN_MACADDR_COUNT]);
+ if (mvi->mvi_maccount > 0) {
+ uint32_t i;
+
+ nla = nla_data(tb[IFLA_MACVLAN_MACADDR_DATA]);
+ len = nla_len(tb[IFLA_MACVLAN_MACADDR_DATA]);
+
+ mvi->mvi_macaddr = calloc(mvi->mvi_maccount,
+ sizeof(*(mvi->mvi_macaddr)));
+
+ i = 0;
+ for (; nla_ok(nla, len); nla = nla_next(nla, &len)) {
+ if (i >= mvi->mvi_maccount)
+ break;
+ if (nla_type(nla) != IFLA_MACVLAN_MACADDR ||
+ nla_len(nla) < ETH_ALEN)
+ continue;
+ mvi->mvi_macaddr[i] = nl_addr_alloc_attr(nla, AF_LLC);
+ i++;
+ }
+ }
+ mvi->mvi_mask |= MACVLAN_HAS_MACADDR;
+ }
+
err = 0;
errout:
return err;
@@ -97,30 +145,54 @@ errout:
static void macvlan_free(struct rtnl_link *link)
{
- free(link->l_info);
+ struct macvlan_info *mvi;
+ uint32_t i;
+
+ mvi = link->l_info;
+
+ for (i = 0; i < mvi->mvi_maccount; i++)
+ nl_addr_put(mvi->mvi_macaddr[i]);
+ free(mvi->mvi_macaddr);
+ free(mvi);
+
link->l_info = NULL;
}
-static void macvlan_dump(struct rtnl_link *link, struct nl_dump_params *p)
+static void macvlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
{
char buf[64];
+ uint32_t i;
struct macvlan_info *mvi = link->l_info;
if (mvi->mvi_mask & MACVLAN_HAS_MODE) {
rtnl_link_macvlan_mode2str(mvi->mvi_mode, buf, sizeof(buf));
- nl_dump(p, "macvlan-mode %s", buf);
+ nl_dump(p, " %s-mode %s", link->l_info_ops->io_name, buf);
}
if (mvi->mvi_mask & MACVLAN_HAS_FLAGS) {
rtnl_link_macvlan_flags2str(mvi->mvi_flags, buf, sizeof(buf));
- nl_dump(p, "macvlan-flags %s", buf);
+ nl_dump(p, " %s-flags %s", link->l_info_ops->io_name, buf);
+ }
+
+ if (mvi->mvi_mask & MACVLAN_HAS_MACADDR) {
+ nl_dump(p, " macvlan-count %u", (unsigned) mvi->mvi_maccount);
+
+ if (mvi->mvi_maccount)
+ nl_dump(p, " macvlan-sourcemac");
+
+ for (i = 0; i < mvi->mvi_maccount; i++) {
+ nl_dump(p, " %s", nl_addr2str(mvi->mvi_macaddr[i], buf,
+ sizeof(buf)));
+ }
}
+ nl_dump(p, "\n");
}
static int macvlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
{
struct macvlan_info *vdst, *vsrc = src->l_info;
int err;
+ uint32_t i;
dst->l_info = NULL;
if ((err = rtnl_link_set_type(dst, "macvlan")) < 0)
@@ -132,41 +204,80 @@ static int macvlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
memcpy(vdst, vsrc, sizeof(struct macvlan_info));
+ if ( vsrc->mvi_mask & MACVLAN_HAS_MACADDR
+ && vsrc->mvi_maccount > 0) {
+ vdst->mvi_macaddr = calloc(vdst->mvi_maccount,
+ sizeof(*(vdst->mvi_macaddr)));
+ for (i = 0; i < vdst->mvi_maccount; i++)
+ vdst->mvi_macaddr[i] = nl_addr_clone(vsrc->mvi_macaddr[i]);
+ } else
+ vdst->mvi_macaddr = NULL;
+
return 0;
}
static int macvlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
{
struct macvlan_info *mvi = link->l_info;
- struct nlattr *data;
+ struct nlattr *data, *datamac = NULL;
+ int i, ret;
if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
return -NLE_MSGSIZE;
+ ret = -NLE_NOMEM;
+
if (mvi->mvi_mask & MACVLAN_HAS_MODE)
NLA_PUT_U32(msg, IFLA_MACVLAN_MODE, mvi->mvi_mode);
if (mvi->mvi_mask & MACVLAN_HAS_FLAGS)
NLA_PUT_U16(msg, IFLA_MACVLAN_FLAGS, mvi->mvi_flags);
- nla_nest_end(msg, data);
+ if (mvi->mvi_mask & MACVLAN_HAS_MACADDR) {
+ NLA_PUT_U32(msg, IFLA_MACVLAN_MACADDR_MODE, mvi->mvi_macmode);
+ datamac = nla_nest_start(msg, IFLA_MACVLAN_MACADDR_DATA);
+ if (!datamac)
+ goto nla_put_failure;
+
+ for (i = 0; i < mvi->mvi_maccount; i++) {
+ NLA_PUT_ADDR(msg, IFLA_MACVLAN_MACADDR,
+ mvi->mvi_macaddr[i]);
+ }
+ }
+
+ ret = 0;
nla_put_failure:
+ if (datamac)
+ nla_nest_end(msg, datamac);
- return 0;
+ nla_nest_end(msg, data);
+
+ return ret;
}
static struct rtnl_link_info_ops macvlan_info_ops = {
- .io_name = "macvlan",
- .io_alloc = macvlan_alloc,
- .io_parse = macvlan_parse,
+ .io_name = "macvlan",
+ .io_alloc = macvlan_alloc,
+ .io_parse = macvlan_parse,
.io_dump = {
- [NL_DUMP_LINE] = macvlan_dump,
- [NL_DUMP_DETAILS] = macvlan_dump,
+ [NL_DUMP_DETAILS] = macvlan_dump_details,
},
- .io_clone = macvlan_clone,
- .io_put_attrs = macvlan_put_attrs,
- .io_free = macvlan_free,
+ .io_clone = macvlan_clone,
+ .io_put_attrs = macvlan_put_attrs,
+ .io_free = macvlan_free,
+};
+
+static struct rtnl_link_info_ops macvtap_info_ops = {
+ .io_name = "macvtap",
+ .io_alloc = macvlan_alloc,
+ .io_parse = macvlan_parse,
+ .io_dump = {
+ [NL_DUMP_DETAILS] = macvlan_dump_details,
+ },
+ .io_clone = macvlan_clone,
+ .io_put_attrs = macvlan_put_attrs,
+ .io_free = macvlan_free,
};
/** @cond SKIP */
@@ -175,6 +286,12 @@ static struct rtnl_link_info_ops macvlan_info_ops = {
APPBUG("Link is not a macvlan link. set type \"macvlan\" first."); \
return -NLE_OPNOTSUPP; \
}
+
+#define IS_MACVTAP_LINK_ASSERT(link) \
+ if ((link)->l_info_ops != &macvtap_info_ops) { \
+ APPBUG("Link is not a macvtap link. set type \"macvtap\" first."); \
+ return -NLE_OPNOTSUPP; \
+ }
/** @endcond */
/**
@@ -205,7 +322,7 @@ struct rtnl_link *rtnl_link_macvlan_alloc(void)
/**
* Check if link is a MACVLAN link
- * @arg link Link object
+ * @arg link Link object
*
* @return True if link is a MACVLAN link, otherwise false is returned.
*/
@@ -216,26 +333,37 @@ int rtnl_link_is_macvlan(struct rtnl_link *link)
/**
* Set MACVLAN MODE
- * @arg link Link object
- * @arg mode MACVLAN mode
+ * @arg link Link object
+ * @arg mode MACVLAN mode
*
* @return 0 on success or a negative error code
*/
int rtnl_link_macvlan_set_mode(struct rtnl_link *link, uint32_t mode)
{
struct macvlan_info *mvi = link->l_info;
+ int i;
IS_MACVLAN_LINK_ASSERT(link);
mvi->mvi_mode = mode;
mvi->mvi_mask |= MACVLAN_HAS_MODE;
+ if (mode != MACVLAN_MODE_SOURCE) {
+ for (i = 0; i < mvi->mvi_maccount; i++)
+ nl_addr_put(mvi->mvi_macaddr[i]);
+ free(mvi->mvi_macaddr);
+ mvi->mvi_maccount = 0;
+ mvi->mvi_macaddr = NULL;
+ mvi->mvi_macmode = MACVLAN_MACADDR_SET;
+ mvi->mvi_mask &= ~MACVLAN_HAS_MACADDR;
+ }
+
return 0;
}
/**
* Get MACVLAN Mode
- * @arg link Link object
+ * @arg link Link object
*
* @return MACVLAN mode, 0 if not set or a negative error code.
*/
@@ -252,9 +380,61 @@ uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *link)
}
/**
+ * Set MACVLAN MACMODE
+ * @arg link Link object
+ * @arg mode MACVLAN mac list modification mode
+ *
+ * Only for macvlan SOURCE mode.
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_macvlan_set_macmode(struct rtnl_link *link, uint32_t macmode)
+{
+ struct macvlan_info *mvi = link->l_info;
+
+ IS_MACVLAN_LINK_ASSERT(link);
+
+ if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
+ (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
+ return -NLE_INVAL;
+
+ mvi->mvi_macmode = macmode;
+ mvi->mvi_mask |= MACVLAN_HAS_MACADDR;
+
+ return 0;
+}
+
+/**
+ * Get MACVLAN MACMODE
+ * @arg link Link object
+ * @arg out_macmode mac list modification mode
+ *
+ * Only for SOURCE mode.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_macvlan_get_macmode(struct rtnl_link *link, uint32_t *out_macmode)
+{
+ struct macvlan_info *mvi = link->l_info;
+
+ IS_MACVLAN_LINK_ASSERT(link);
+
+ if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
+ (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
+ return -NLE_INVAL;
+
+ if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
+ return -NLE_INVAL;
+
+ *out_macmode = mvi->mvi_macmode;
+
+ return 0;
+}
+
+/**
* Set MACVLAN flags
- * @arg link Link object
- * @arg flags MACVLAN flags
+ * @arg link Link object
+ * @arg flags MACVLAN flags
*
* @return 0 on success or a negative error code.
*/
@@ -272,8 +452,8 @@ int rtnl_link_macvlan_set_flags(struct rtnl_link *link, uint16_t flags)
/**
* Unset MACVLAN flags
- * @arg link Link object
- * @arg flags MACVLAN flags
+ * @arg link Link object
+ * @arg flags MACVLAN flags
*
* Note: kernel currently only has a single flag and lacks flags_mask to
* indicate which flags shall be changed (it always all).
@@ -294,7 +474,7 @@ int rtnl_link_macvlan_unset_flags(struct rtnl_link *link, uint16_t flags)
/**
* Get MACVLAN flags
- * @arg link Link object
+ * @arg link Link object
*
* @return MACVLAN flags, 0 if none set, or a negative error code.
*/
@@ -307,17 +487,309 @@ uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *link)
return mvi->mvi_flags;
}
+/**
+ * Get number of MAC-Addr for MACVLAN device in source mode
+ * @arg link Link object
+ * @arg out_count number of mac addresses
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_macvlan_count_macaddr(struct rtnl_link *link, uint32_t *out_count)
+{
+ struct macvlan_info *mvi = link->l_info;
+
+ IS_MACVLAN_LINK_ASSERT(link);
+
+ if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
+ (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
+ return -NLE_INVAL;
+
+ if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
+ return -NLE_INVAL;
+
+ *out_count = mvi->mvi_maccount;
+
+ return 0;
+}
+
+/**
+ * Get configured remote MAC-Addr from MACVLAN device in source mode
+ * @arg link Link object
+ * @arg out_addr address object
+ *
+ * The returned nl_addr struct needs NOT to be released using nl_addr_put.
+ * It is only valid until the address is not removed from this link object
+ * or its mode is changed to non-source.
+ *
+ * @return 0 on success or negative error code
+ */
+int rtnl_link_macvlan_get_macaddr(struct rtnl_link *link, uint32_t idx,
+ const struct nl_addr **out_addr)
+{
+ struct macvlan_info *mvi = link->l_info;
+
+ IS_MACVLAN_LINK_ASSERT(link);
+
+ if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
+ (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
+ return -NLE_INVAL;
+
+ if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
+ return -NLE_INVAL;
+
+ if (idx >= mvi->mvi_maccount)
+ return -NLE_INVAL;
+
+ *out_addr = mvi->mvi_macaddr[idx];
+ return 0;
+}
+
+/**
+ * Add MAC-Addr to MACVLAN device in source mode
+ * @arg link Link object
+ * @arg addr MAC-Addr
+ *
+ * addr is not release but cloned by this method.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_macvlan_add_macaddr(struct rtnl_link *link, struct nl_addr *addr)
+{
+ struct macvlan_info *mvi = link->l_info;
+ struct nl_addr **mvi_macaddr;
+ size_t newsize;
+
+ IS_MACVLAN_LINK_ASSERT(link);
+
+ if (nl_addr_get_family(addr) != AF_LLC)
+ return -NLE_INVAL;
+
+ if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
+ (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
+ return -NLE_INVAL;
+
+ if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
+ return -NLE_INVAL;
+
+ if (mvi->mvi_maccount >= UINT32_MAX)
+ return -NLE_INVAL;
+
+ newsize = (mvi->mvi_maccount + 1) * sizeof(*(mvi->mvi_macaddr));
+ mvi_macaddr = realloc(mvi->mvi_macaddr, newsize);
+ if (!mvi_macaddr)
+ return -NLE_NOMEM;
+
+ mvi->mvi_macaddr = mvi_macaddr;
+ mvi->mvi_macaddr[mvi->mvi_maccount] = nl_addr_clone(addr);
+ mvi->mvi_maccount++;
+
+ mvi->mvi_mask |= MACVLAN_HAS_MACADDR;
+
+ return 0;
+}
+
+/**
+ * Remove MAC-Addr from MACVLAN device in source mode
+ * @arg link Link object
+ * @arg addr MAC-Addr
+ *
+ * addr is not release by this method.
+ *
+ * @return a negative error code on failure, or the number
+ * of deleted addresses on success.
+ */
+int rtnl_link_macvlan_del_macaddr(struct rtnl_link *link, struct nl_addr *addr)
+{
+ struct macvlan_info *mvi = link->l_info;
+ uint32_t found, i;
+
+ IS_MACVLAN_LINK_ASSERT(link);
+
+ if (nl_addr_get_family(addr) != AF_LLC)
+ return -NLE_INVAL;
+
+ if (!(mvi->mvi_mask & MACVLAN_HAS_MODE) ||
+ (mvi->mvi_mode != MACVLAN_MODE_SOURCE))
+ return -NLE_INVAL;
+
+ if (!(mvi->mvi_mask & MACVLAN_HAS_MACADDR))
+ return -NLE_INVAL;
+
+ nl_addr_get(addr);
+
+ found = 0; i = 0;
+ while (i + found < mvi->mvi_maccount) {
+ mvi->mvi_macaddr[i] = mvi->mvi_macaddr[i + found];
+ if (found > 0)
+ mvi->mvi_macaddr[i + found] = NULL;
+ if (nl_addr_cmp(addr, mvi->mvi_macaddr[i]) == 0) {
+ nl_addr_put(mvi->mvi_macaddr[i]);
+ mvi->mvi_macaddr[i] = NULL;
+ found++;
+ } else
+ i++;
+ }
+
+ nl_addr_put(addr);
+
+ mvi->mvi_maccount -= found;
+
+ return found > INT_MAX ? INT_MAX : (int) found;
+}
+
+/** @} */
+
+
+/**
+ * @name MACVTAP Object
+ * @{
+ */
+
+/**
+ * Allocate link object of type MACVTAP
+ *
+ * @return Allocated link object or NULL.
+ */
+struct rtnl_link *rtnl_link_macvtap_alloc(void)
+{
+ struct rtnl_link *link;
+ int err;
+
+ if (!(link = rtnl_link_alloc()))
+ return NULL;
+
+ if ((err = rtnl_link_set_type(link, "macvtap")) < 0) {
+ rtnl_link_put(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/**
+ * Check if link is a MACVTAP link
+ * @arg link Link object
+ *
+ * @return True if link is a MACVTAP link, otherwise false is returned.
+ */
+int rtnl_link_is_macvtap(struct rtnl_link *link)
+{
+ return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "macvtap");
+}
+
+/**
+ * Set MACVTAP MODE
+ * @arg link Link object
+ * @arg mode MACVTAP mode
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_macvtap_set_mode(struct rtnl_link *link, uint32_t mode)
+{
+ struct macvlan_info *mvi = link->l_info;
+
+ IS_MACVTAP_LINK_ASSERT(link);
+
+ mvi->mvi_mode = mode;
+ mvi->mvi_mask |= MACVLAN_HAS_MODE;
+
+ return 0;
+}
+
+/**
+ * Get MACVTAP Mode
+ * @arg link Link object
+ *
+ * @return MACVTAP mode, 0 if not set or a negative error code.
+ */
+uint32_t rtnl_link_macvtap_get_mode(struct rtnl_link *link)
+{
+ struct macvlan_info *mvi = link->l_info;
+
+ IS_MACVTAP_LINK_ASSERT(link);
+
+ if (mvi->mvi_mask & MACVLAN_HAS_MODE)
+ return mvi->mvi_mode;
+ else
+ return 0;
+}
+
+/**
+ * Set MACVTAP flags
+ * @arg link Link object
+ * @arg flags MACVTAP flags
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_macvtap_set_flags(struct rtnl_link *link, uint16_t flags)
+{
+ struct macvlan_info *mvi = link->l_info;
+
+ IS_MACVTAP_LINK_ASSERT(link);
+
+ mvi->mvi_flags |= flags;
+ mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
+
+ return 0;
+}
+
+/**
+ * Unset MACVTAP flags
+ * @arg link Link object
+ * @arg flags MACVTAP flags
+ *
+ * Note: kernel currently only has a single flag and lacks flags_mask to
+ * indicate which flags shall be changed (it always all).
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_macvtap_unset_flags(struct rtnl_link *link, uint16_t flags)
+{
+ struct macvlan_info *mvi = link->l_info;
+
+ IS_MACVTAP_LINK_ASSERT(link);
+
+ mvi->mvi_flags &= ~flags;
+ mvi->mvi_mask |= MACVLAN_HAS_FLAGS;
+
+ return 0;
+}
+
+/**
+ * Get MACVTAP flags
+ * @arg link Link object
+ *
+ * @return MACVTAP flags, 0 if none set, or a negative error code.
+ */
+uint16_t rtnl_link_macvtap_get_flags(struct rtnl_link *link)
+{
+ struct macvlan_info *mvi = link->l_info;
+
+ IS_MACVTAP_LINK_ASSERT(link);
+
+ return mvi->mvi_flags;
+}
+
/** @} */
+
static const struct trans_tbl macvlan_flags[] = {
- __ADD(MACVLAN_FLAG_NOPROMISC, nopromisc)
+ __ADD(MACVLAN_FLAG_NOPROMISC, nopromisc),
};
static const struct trans_tbl macvlan_modes[] = {
- __ADD(MACVLAN_MODE_PRIVATE, private)
- __ADD(MACVLAN_MODE_VEPA, vepa)
- __ADD(MACVLAN_MODE_BRIDGE, bridge)
- __ADD(MACVLAN_MODE_PASSTHRU, passthru)
+ __ADD(MACVLAN_MODE_PRIVATE, private),
+ __ADD(MACVLAN_MODE_VEPA, vepa),
+ __ADD(MACVLAN_MODE_BRIDGE, bridge),
+ __ADD(MACVLAN_MODE_PASSTHRU, passthru),
+ __ADD(MACVLAN_MODE_SOURCE, source),
+};
+
+static const struct trans_tbl macvlan_macmodes[] = {
+ __ADD(MACVLAN_MACADDR_ADD, "add"),
+ __ADD(MACVLAN_MACADDR_DEL, "del"),
+ __ADD(MACVLAN_MACADDR_SET, "set"),
+ __ADD(MACVLAN_MACADDR_FLUSH, "flush"),
};
/**
@@ -335,6 +807,16 @@ int rtnl_link_macvlan_str2flags(const char *name)
return __str2flags(name, macvlan_flags, ARRAY_SIZE(macvlan_flags));
}
+char *rtnl_link_macvtap_flags2str(int flags, char *buf, size_t len)
+{
+ return __flags2str(flags, buf, len, macvlan_flags, ARRAY_SIZE(macvlan_flags));
+}
+
+int rtnl_link_macvtap_str2flags(const char *name)
+{
+ return __str2flags(name, macvlan_flags, ARRAY_SIZE(macvlan_flags));
+}
+
/** @} */
/**
@@ -352,16 +834,39 @@ int rtnl_link_macvlan_str2mode(const char *name)
return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
}
+char *rtnl_link_macvlan_macmode2str(int mode, char *buf, size_t len)
+{
+ return __type2str(mode, buf, len, macvlan_macmodes,
+ ARRAY_SIZE(macvlan_macmodes));
+}
+
+int rtnl_link_macvlan_str2macmode(const char *name)
+{
+ return __str2type(name, macvlan_macmodes, ARRAY_SIZE(macvlan_macmodes));
+}
+
+char *rtnl_link_macvtap_mode2str(int mode, char *buf, size_t len)
+{
+ return __type2str(mode, buf, len, macvlan_modes, ARRAY_SIZE(macvlan_modes));
+}
+
+int rtnl_link_macvtap_str2mode(const char *name)
+{
+ return __str2type(name, macvlan_modes, ARRAY_SIZE(macvlan_modes));
+}
+
/** @} */
static void __init macvlan_init(void)
{
rtnl_link_register_info(&macvlan_info_ops);
+ rtnl_link_register_info(&macvtap_info_ops);
}
static void __exit macvlan_exit(void)
{
rtnl_link_unregister_info(&macvlan_info_ops);
+ rtnl_link_unregister_info(&macvtap_info_ops);
}
/** @} */
diff --git a/lib/route/link/ppp.c b/lib/route/link/ppp.c
new file mode 100644
index 00000000..b05e7f3f
--- /dev/null
+++ b/lib/route/link/ppp.c
@@ -0,0 +1,224 @@
+/*
+ * lib/route/link/ppp.c PPP Link Module
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2016 Jonas Johansson <jonasj76@gmail.com>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup ppp PPP
+ *
+ * @details
+ * \b Link Type Name: "ppp"
+ *
+ * @route_doc{link_ppp, PPP Documentation}
+ * @{
+ */
+
+#include <netlink/route/link/ppp.h>
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink-private/route/link/api.h>
+
+/** @cond SKIP */
+#define PPP_ATTR_FD (1<<0)
+
+struct ppp_info
+{
+ int32_t pi_fd;
+ uint32_t ce_mask;
+};
+
+/** @endcond */
+
+static struct nla_policy ppp_nl_policy[IFLA_PPP_MAX+1] = {
+ [IFLA_PPP_DEV_FD] = { .type = NLA_S32 },
+};
+
+static int ppp_alloc(struct rtnl_link *link)
+{
+ struct ppp_info *info;
+
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*info));
+ else {
+ if ((info = calloc(1, sizeof(*info))) == NULL)
+ return -NLE_NOMEM;
+
+ link->l_info = info;
+ }
+
+ return 0;
+}
+
+static int ppp_parse(struct rtnl_link *link, struct nlattr *data,
+ struct nlattr *xstats)
+{
+ struct nlattr *tb[IFLA_PPP_MAX+1];
+ struct ppp_info *info;
+ int err;
+
+ NL_DBG(3, "Parsing PPP link info\n");
+
+ if ((err = nla_parse_nested(tb, IFLA_PPP_MAX, data, ppp_nl_policy)) < 0)
+ goto errout;
+
+ if ((err = ppp_alloc(link)) < 0)
+ goto errout;
+
+ info = link->l_info;
+
+ if (tb[IFLA_PPP_DEV_FD]) {
+ info->pi_fd = nla_get_s32(tb[IFLA_PPP_DEV_FD]);
+ info->ce_mask |= PPP_ATTR_FD;
+ }
+
+ err = 0;
+errout:
+ return err;
+}
+
+static void ppp_free(struct rtnl_link *link)
+{
+ free(link->l_info);
+ link->l_info = NULL;
+}
+
+static int ppp_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+ struct ppp_info *vdst, *vsrc = src->l_info;
+ int err;
+
+ dst->l_info = NULL;
+ if ((err = rtnl_link_set_type(dst, "ppp")) < 0)
+ return err;
+ vdst = dst->l_info;
+
+ if (!vdst || !vsrc)
+ return -NLE_NOMEM;
+
+ memcpy(vdst, vsrc, sizeof(struct ppp_info));
+
+ return 0;
+}
+
+static int ppp_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+ struct ppp_info *info = link->l_info;
+ struct nlattr *data;
+
+ if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+ return -NLE_MSGSIZE;
+
+ if (info->ce_mask & PPP_ATTR_FD)
+ NLA_PUT_S32(msg, IFLA_PPP_DEV_FD, info->pi_fd);
+
+ nla_nest_end(msg, data);
+
+nla_put_failure:
+
+ return 0;
+}
+
+static struct rtnl_link_info_ops ppp_info_ops = {
+ .io_name = "ppp",
+ .io_alloc = ppp_alloc,
+ .io_parse = ppp_parse,
+ .io_clone = ppp_clone,
+ .io_put_attrs = ppp_put_attrs,
+ .io_free = ppp_free,
+};
+
+/** @cond SKIP */
+#define IS_PPP_LINK_ASSERT(link) \
+ if ((link)->l_info_ops != &ppp_info_ops) { \
+ APPBUG("Link is not a PPP link. set type \"ppp\" first."); \
+ return -NLE_OPNOTSUPP; \
+ }
+/** @endcond */
+
+/**
+ * @name PPP Object
+ * @{
+ */
+
+/**
+ * Allocate link object of type PPP
+ *
+ * @return Allocated link object or NULL.
+ */
+struct rtnl_link *rtnl_link_ppp_alloc(void)
+{
+ struct rtnl_link *link;
+ int err;
+
+ if (!(link = rtnl_link_alloc()))
+ return NULL;
+
+ if ((err = rtnl_link_set_type(link, "ppp")) < 0) {
+ rtnl_link_put(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/**
+ * Set PPP file descriptor
+ * @arg link Link object
+ * @arg flags PPP file descriptor
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_ppp_set_fd(struct rtnl_link *link, int32_t fd)
+{
+ struct ppp_info *info = link->l_info;
+
+ IS_PPP_LINK_ASSERT(link);
+
+ info->pi_fd |= fd;
+ info->ce_mask |= PPP_ATTR_FD;
+
+ return 0;
+}
+
+/**
+ * Get PPP file descriptor
+ * @arg link Link object
+ *
+ * @return PPP file descriptor, 0 if not set or a negative error code.
+ */
+int rtnl_link_ppp_get_fd(struct rtnl_link *link, int32_t *fd)
+{
+ struct ppp_info *info = link->l_info;
+
+ IS_PPP_LINK_ASSERT(link);
+
+ if (!(info->ce_mask & PPP_ATTR_FD))
+ return -NLE_NOATTR;
+
+ if (fd)
+ *fd = info->pi_fd;
+
+ return 0;
+}
+
+/** @} */
+
+static void __init ppp_init(void)
+{
+ rtnl_link_register_info(&ppp_info_ops);
+}
+
+static void __exit ppp_exit(void)
+{
+ rtnl_link_unregister_info(&ppp_info_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/sit.c b/lib/route/link/sit.c
index 694c177f..88565137 100644
--- a/lib/route/link/sit.c
+++ b/lib/route/link/sit.c
@@ -28,6 +28,7 @@
#include <netlink/utils.h>
#include <netlink/object.h>
#include <netlink/route/rtnl.h>
+#include <netlink/route/link/sit.h>
#include <netlink-private/route/link/api.h>
#include <linux/if_tunnel.h>
@@ -39,6 +40,10 @@
#define SIT_ATTR_PMTUDISC (1 << 5)
#define SIT_ATTR_FLAGS (1 << 6)
#define SIT_ATTR_PROTO (1 << 7)
+#define SIT_ATTR_6RD_PREFIX (1 << 8)
+#define SIT_ATTR_6RD_RELAY_PREFIX (1 << 9)
+#define SIT_ATTR_6RD_PREFIXLEN (1 << 10)
+#define SIT_ATTR_6RD_RELAY_PREFIXLEN (1 << 11)
struct sit_info
{
@@ -50,6 +55,10 @@ struct sit_info
uint32_t link;
uint32_t local;
uint32_t remote;
+ struct in6_addr ip6rd_prefix;
+ uint32_t ip6rd_relay_prefix;
+ uint16_t ip6rd_prefixlen;
+ uint16_t ip6rd_relay_prefixlen;
uint32_t sit_mask;
};
@@ -62,17 +71,25 @@ static struct nla_policy sit_policy[IFLA_IPTUN_MAX + 1] = {
[IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 },
[IFLA_IPTUN_FLAGS] = { .type = NLA_U16 },
[IFLA_IPTUN_PROTO] = { .type = NLA_U8 },
+ [IFLA_IPTUN_6RD_PREFIX] = { .minlen = sizeof(struct in6_addr) },
+ [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NLA_U32 },
+ [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 },
+ [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 },
};
static int sit_alloc(struct rtnl_link *link)
{
struct sit_info *sit;
- sit = calloc(1, sizeof(*sit));
- if (!sit)
- return -NLE_NOMEM;
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*sit));
+ else {
+ sit = calloc(1, sizeof(*sit));
+ if (!sit)
+ return -NLE_NOMEM;
- link->l_info = sit;
+ link->l_info = sit;
+ }
return 0;
}
@@ -84,7 +101,7 @@ static int sit_parse(struct rtnl_link *link, struct nlattr *data,
struct sit_info *sit;
int err;
- NL_DBG(3, "Parsing SIT link info");
+ NL_DBG(3, "Parsing SIT link info\n");
err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, sit_policy);
if (err < 0)
@@ -136,9 +153,30 @@ static int sit_parse(struct rtnl_link *link, struct nlattr *data,
sit->sit_mask |= SIT_ATTR_PROTO;
}
+ if (tb[IFLA_IPTUN_6RD_PREFIX]) {
+ nla_memcpy(&sit->ip6rd_prefix, tb[IFLA_IPTUN_6RD_PREFIX],
+ sizeof(struct in6_addr));
+ sit->sit_mask |= SIT_ATTR_6RD_PREFIX;
+ }
+
+ if (tb[IFLA_IPTUN_6RD_RELAY_PREFIX]) {
+ sit->ip6rd_relay_prefix = nla_get_u32(tb[IFLA_IPTUN_6RD_RELAY_PREFIX]);
+ sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIX;
+ }
+
+ if (tb[IFLA_IPTUN_6RD_PREFIXLEN]) {
+ sit->ip6rd_prefixlen = nla_get_u16(tb[IFLA_IPTUN_6RD_PREFIXLEN]);
+ sit->sit_mask |= SIT_ATTR_6RD_PREFIXLEN;
+ }
+
+ if (tb[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) {
+ sit->ip6rd_relay_prefixlen = nla_get_u16(tb[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
+ sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIXLEN;
+ }
+
err = 0;
- errout:
+errout:
return err;
}
@@ -175,6 +213,18 @@ static int sit_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
if (sit->sit_mask & SIT_ATTR_PROTO)
NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, sit->proto);
+ if (sit->sit_mask & SIT_ATTR_6RD_PREFIX)
+ NLA_PUT(msg, IFLA_IPTUN_6RD_PREFIX, sizeof(struct in6_addr), &sit->ip6rd_prefix);
+
+ if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX)
+ NLA_PUT_U32(msg, IFLA_IPTUN_6RD_RELAY_PREFIX, sit->ip6rd_relay_prefix);
+
+ if (sit->sit_mask & SIT_ATTR_6RD_PREFIXLEN)
+ NLA_PUT_U16(msg, IFLA_IPTUN_6RD_PREFIXLEN, sit->ip6rd_prefixlen);
+
+ if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIXLEN)
+ NLA_PUT_U16(msg, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, sit->ip6rd_relay_prefixlen);
+
nla_nest_end(msg, data);
nla_put_failure:
@@ -198,11 +248,17 @@ static void sit_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
static void sit_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
{
struct sit_info *sit = link->l_info;
- char *name, addr[INET_ADDRSTRLEN];
+ char *name, addr[INET_ADDRSTRLEN], addr6[INET6_ADDRSTRLEN];
+ struct rtnl_link *parent;
if (sit->sit_mask & SIT_ATTR_LINK) {
nl_dump(p, " link ");
- name = rtnl_link_get_name(link);
+
+ name = NULL;
+ parent = link_lookup(link->ce_cache, sit->link);
+ if (parent)
+ name = rtnl_link_get_name(parent);
+
if (name)
nl_dump_line(p, "%s\n", name);
else
@@ -241,9 +297,35 @@ static void sit_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
}
if (sit->sit_mask & SIT_ATTR_PROTO) {
- nl_dump(p, " proto ");
+ nl_dump(p, " proto ");
nl_dump_line(p, " (%x)\n", sit->proto);
}
+
+ if (sit->sit_mask & SIT_ATTR_6RD_PREFIX) {
+ nl_dump(p, " 6rd_prefix ");
+ if(inet_ntop(AF_INET6, &sit->ip6rd_prefix, addr6, INET6_ADDRSTRLEN))
+ nl_dump_line(p, "%s\n", addr6);
+ else
+ nl_dump_line(p, "[unknown]\n");
+ }
+
+ if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX) {
+ nl_dump(p, " 6rd_relay_prefix ");
+ if(inet_ntop(AF_INET, &sit->ip6rd_relay_prefix, addr, sizeof(addr)))
+ nl_dump_line(p, "%s\n", addr);
+ else
+ nl_dump_line(p, "[unknown]\n");
+ }
+
+ if (sit->sit_mask & SIT_ATTR_6RD_PREFIXLEN) {
+ nl_dump(p, " 6rd_prefixlen ");
+ nl_dump_line(p, "%d\n", sit->ip6rd_prefixlen);
+ }
+
+ if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIXLEN) {
+ nl_dump(p, " 6rd_relay_prefixlen ");
+ nl_dump_line(p, "%d\n", sit->ip6rd_relay_prefixlen);
+ }
}
static int sit_clone(struct rtnl_link *dst, struct rtnl_link *src)
@@ -280,11 +362,16 @@ static struct rtnl_link_info_ops sit_info_ops = {
.io_free = sit_free,
};
-#define IS_SIT_LINK_ASSERT(link) \
- if ((link)->l_info_ops != &sit_info_ops) { \
- APPBUG("Link is not a sit link. set type \"sit\" first."); \
- return -NLE_OPNOTSUPP; \
- }
+#define IS_SIT_LINK_ASSERT(link, sit) \
+ struct sit_info *sit; \
+ do { \
+ const struct rtnl_link *_link = (link); \
+ if (!_link || _link->l_info_ops != &sit_info_ops) { \
+ APPBUG("Link is not a sit link. set type \"sit\" first."); \
+ return -NLE_OPNOTSUPP; \
+ } \
+ (sit) = _link->l_info; \
+ } while (0)
struct rtnl_link *rtnl_link_sit_alloc(void)
{
@@ -350,9 +437,7 @@ int rtnl_link_sit_add(struct nl_sock *sk, const char *name)
*/
int rtnl_link_sit_set_link(struct rtnl_link *link, uint32_t index)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
sit->link = index;
sit->sit_mask |= SIT_ATTR_LINK;
@@ -368,9 +453,7 @@ int rtnl_link_sit_set_link(struct rtnl_link *link, uint32_t index)
*/
uint32_t rtnl_link_sit_get_link(struct rtnl_link *link)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
return sit->link;
}
@@ -384,9 +467,7 @@ uint32_t rtnl_link_sit_get_link(struct rtnl_link *link)
*/
int rtnl_link_sit_set_local(struct rtnl_link *link, uint32_t addr)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
sit->local = addr;
sit->sit_mask |= SIT_ATTR_LOCAL;
@@ -402,9 +483,7 @@ int rtnl_link_sit_set_local(struct rtnl_link *link, uint32_t addr)
*/
uint32_t rtnl_link_sit_get_local(struct rtnl_link *link)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
return sit->local;
}
@@ -418,9 +497,7 @@ uint32_t rtnl_link_sit_get_local(struct rtnl_link *link)
*/
int rtnl_link_sit_set_remote(struct rtnl_link *link, uint32_t addr)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
sit->remote = addr;
sit->sit_mask |= SIT_ATTR_REMOTE;
@@ -436,9 +513,7 @@ int rtnl_link_sit_set_remote(struct rtnl_link *link, uint32_t addr)
*/
uint32_t rtnl_link_sit_get_remote(struct rtnl_link *link)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
return sit->remote;
}
@@ -452,9 +527,7 @@ uint32_t rtnl_link_sit_get_remote(struct rtnl_link *link)
*/
int rtnl_link_sit_set_ttl(struct rtnl_link *link, uint8_t ttl)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
sit->ttl = ttl;
sit->sit_mask |= SIT_ATTR_TTL;
@@ -470,9 +543,7 @@ int rtnl_link_sit_set_ttl(struct rtnl_link *link, uint8_t ttl)
*/
uint8_t rtnl_link_sit_get_ttl(struct rtnl_link *link)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
return sit->ttl;
}
@@ -486,9 +557,7 @@ uint8_t rtnl_link_sit_get_ttl(struct rtnl_link *link)
*/
int rtnl_link_sit_set_tos(struct rtnl_link *link, uint8_t tos)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
sit->tos = tos;
sit->sit_mask |= SIT_ATTR_TOS;
@@ -504,9 +573,7 @@ int rtnl_link_sit_set_tos(struct rtnl_link *link, uint8_t tos)
*/
uint8_t rtnl_link_sit_get_tos(struct rtnl_link *link)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
return sit->tos;
}
@@ -520,9 +587,7 @@ uint8_t rtnl_link_sit_get_tos(struct rtnl_link *link)
*/
int rtnl_link_sit_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
sit->pmtudisc = pmtudisc;
sit->sit_mask |= SIT_ATTR_PMTUDISC;
@@ -538,9 +603,7 @@ int rtnl_link_sit_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc)
*/
uint8_t rtnl_link_sit_get_pmtudisc(struct rtnl_link *link)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
return sit->pmtudisc;
}
@@ -554,9 +617,7 @@ uint8_t rtnl_link_sit_get_pmtudisc(struct rtnl_link *link)
*/
int rtnl_link_sit_set_flags(struct rtnl_link *link, uint16_t flags)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
sit->flags = flags;
sit->sit_mask |= SIT_ATTR_FLAGS;
@@ -572,9 +633,7 @@ int rtnl_link_sit_set_flags(struct rtnl_link *link, uint16_t flags)
*/
uint16_t rtnl_link_sit_get_flags(struct rtnl_link *link)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
return sit->flags;
}
@@ -588,9 +647,7 @@ uint16_t rtnl_link_sit_get_flags(struct rtnl_link *link)
*/
int rtnl_link_sit_set_proto(struct rtnl_link *link, uint8_t proto)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
sit->proto = proto;
sit->sit_mask |= SIT_ATTR_PROTO;
@@ -606,13 +663,155 @@ int rtnl_link_sit_set_proto(struct rtnl_link *link, uint8_t proto)
*/
uint8_t rtnl_link_sit_get_proto(struct rtnl_link *link)
{
- struct sit_info *sit = link->l_info;
-
- IS_SIT_LINK_ASSERT(link);
+ IS_SIT_LINK_ASSERT(link, sit);
return sit->proto;
}
+/**
+ * Set ip6rd prefix
+ * @arg link Link object
+ * @arg prefix The IPv6 prefix
+ *
+ * @return 0 on success or an error code.
+ */
+int rtnl_link_sit_set_ip6rd_prefix(struct rtnl_link *link, const struct in6_addr *prefix)
+{
+ IS_SIT_LINK_ASSERT(link, sit);
+
+ sit->ip6rd_prefix = *prefix;
+ sit->sit_mask |= SIT_ATTR_6RD_PREFIX;
+ return 0;
+}
+
+/**
+ * Get ip6rd prefix
+ * @arg link Link object
+ * @arg prefix The output IPv6 prefix
+ *
+ * @return 0 on success or an error code. If the property is unset,
+ * this call fails too.
+ */
+int rtnl_link_sit_get_ip6rd_prefix(const struct rtnl_link *link, struct in6_addr *prefix)
+{
+ IS_SIT_LINK_ASSERT(link, sit);
+
+ if (!(sit->sit_mask & SIT_ATTR_6RD_PREFIX))
+ return -NLE_NOATTR;
+
+ if (prefix)
+ *prefix = sit->ip6rd_prefix;
+ return 0;
+}
+
+/**
+ * Set ip6rd prefix length
+ * @arg link Link object
+ * @arg prefixlen The IPv6 prefix length
+ *
+ * @return 0 on success or an error code.
+ */
+int rtnl_link_sit_set_ip6rd_prefixlen(struct rtnl_link *link, uint16_t prefixlen)
+{
+ IS_SIT_LINK_ASSERT(link, sit);
+
+ sit->sit_mask |= SIT_ATTR_6RD_PREFIXLEN;
+ sit->ip6rd_prefixlen = prefixlen;
+ return 0;
+}
+
+/**
+ * Get ip6rd prefix length
+ * @arg link Link object
+ * @arg prefixlen Output pointer for the prefix length
+ *
+ * @return 0 on success or an error code. If the property is unset,
+ * this call fails.
+ */
+int rtnl_link_sit_get_ip6rd_prefixlen(struct rtnl_link *link, uint16_t *prefixlen)
+{
+ IS_SIT_LINK_ASSERT(link, sit);
+
+ if (!(sit->sit_mask & SIT_ATTR_6RD_PREFIXLEN))
+ return -NLE_NOATTR;
+
+ if (prefixlen)
+ *prefixlen = sit->ip6rd_prefixlen;
+ return 0;
+}
+
+/**
+ * Set ip6rd relay prefix
+ * @arg link Link object
+ * @arg prefix The IPv6 prefix length
+ *
+ * @return 0 on success or an error code.
+ */
+int rtnl_link_sit_set_ip6rd_relay_prefix(struct rtnl_link *link, uint32_t prefix)
+{
+ IS_SIT_LINK_ASSERT(link, sit);
+
+ sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIX;
+ sit->ip6rd_relay_prefix = prefix;
+ return 0;
+}
+
+/**
+ * Get ip6rd prefix length
+ * @arg link Link object
+ * @arg prefixlen Output pointer for the prefix length
+ *
+ * @return 0 on success or an error code. If the property is unset,
+ * this call fails.
+ */
+int rtnl_link_sit_get_ip6rd_relay_prefix(const struct rtnl_link *link, uint32_t *prefix)
+{
+ IS_SIT_LINK_ASSERT(link, sit);
+
+ if (!(sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX))
+ return -NLE_NOATTR;
+
+ if (prefix)
+ *prefix = sit->ip6rd_relay_prefix;
+ return 0;
+}
+
+/**
+ * Set ip6rd relay prefix length
+ * @arg link Link object
+ * @arg prefixlen The IPv6 prefix length
+ *
+ * @return 0 on success or an error code.
+ */
+int rtnl_link_sit_set_ip6rd_relay_prefixlen(struct rtnl_link *link, uint16_t prefixlen)
+{
+ IS_SIT_LINK_ASSERT(link, sit);
+
+ sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIXLEN;
+ sit->ip6rd_relay_prefixlen = prefixlen;
+ return 0;
+}
+
+/**
+ * Get ip6rd relay prefix length
+ * @arg link Link object
+ * @arg prefixlen Output pointer for the prefix length
+ *
+ * @return 0 on success or an error code. If the property is unset,
+ * this call fails.
+ */
+int rtnl_link_sit_get_ip6rd_relay_prefixlen(struct rtnl_link *link, uint16_t *prefixlen)
+{
+ IS_SIT_LINK_ASSERT(link, sit);
+
+ if (!(sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX))
+ return -NLE_NOATTR;
+
+ if (prefixlen)
+ *prefixlen = sit->ip6rd_relay_prefixlen;
+ return 0;
+}
+
static void __init sit_init(void)
{
rtnl_link_register_info(&sit_info_ops);
diff --git a/lib/route/link/sriov.c b/lib/route/link/sriov.c
new file mode 100644
index 00000000..2a87cfe5
--- /dev/null
+++ b/lib/route/link/sriov.c
@@ -0,0 +1,1466 @@
+/*
+ * lib/route/link/sriov.c SRIOV VF Info
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2016 Intel Corp. All rights reserved.
+ * Copyright (c) 2016 Jef Oliver <jef.oliver@intel.com>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup sriov SRIOV
+ * SR-IOV VF link module
+ *
+ * @details
+ * SR-IOV (Single Root Input/Output Virtualization) is a network interface
+ * that allows for the isolation of the PCI Express resources. In a virtual
+ * environment, SR-IOV allows multiple virtual machines can share a single
+ * PCI Express hardware interface. This is done via VFs (Virtual Functions),
+ * virtual hardware devices with their own PCI address.
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/route/link/api.h>
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#include <linux/if_ether.h>
+#include <linux/if_link.h>
+#include <netlink-private/route/link/sriov.h>
+#include <netlink/route/link/sriov.h>
+
+/** @cond SKIP */
+
+#define SRIOVON "on"
+#define SRIOVOFF "off"
+
+#define SET_VF_STAT(link, vf_num, stb, stat, attr) \
+ vf_data->vf_stats[stat] = nla_get_u64(stb[attr])
+
+/* SRIOV-VF Attributes */
+#define SRIOV_ATTR_INDEX (1 << 0)
+#define SRIOV_ATTR_ADDR (1 << 1)
+#define SRIOV_ATTR_VLAN (1 << 2)
+#define SRIOV_ATTR_TX_RATE (1 << 3)
+#define SRIOV_ATTR_SPOOFCHK (1 << 4)
+#define SRIOV_ATTR_RATE_MAX (1 << 5)
+#define SRIOV_ATTR_RATE_MIN (1 << 6)
+#define SRIOV_ATTR_LINK_STATE (1 << 7)
+#define SRIOV_ATTR_RSS_QUERY_EN (1 << 8)
+#define SRIOV_ATTR_STATS (1 << 9)
+#define SRIOV_ATTR_TRUST (1 << 10)
+#define SRIOV_ATTR_IB_NODE_GUID (1 << 11)
+#define SRIOV_ATTR_IB_PORT_GUID (1 << 12)
+
+static struct nla_policy sriov_info_policy[IFLA_VF_MAX+1] = {
+ [IFLA_VF_MAC] = { .minlen = sizeof(struct ifla_vf_mac) },
+ [IFLA_VF_VLAN] = { .minlen = sizeof(struct ifla_vf_vlan) },
+ [IFLA_VF_VLAN_LIST] = { .type = NLA_NESTED },
+ [IFLA_VF_TX_RATE] = { .minlen = sizeof(struct ifla_vf_tx_rate) },
+ [IFLA_VF_SPOOFCHK] = { .minlen = sizeof(struct ifla_vf_spoofchk) },
+ [IFLA_VF_RATE] = { .minlen = sizeof(struct ifla_vf_rate) },
+ [IFLA_VF_LINK_STATE] = { .minlen = sizeof(struct ifla_vf_link_state) },
+ [IFLA_VF_RSS_QUERY_EN] = { .minlen = sizeof(struct ifla_vf_rss_query_en) },
+ [IFLA_VF_STATS] = { .type = NLA_NESTED },
+ [IFLA_VF_TRUST] = { .minlen = sizeof(struct ifla_vf_trust) },
+ [IFLA_VF_IB_NODE_GUID] = { .minlen = sizeof(struct ifla_vf_guid) },
+ [IFLA_VF_IB_PORT_GUID] = { .minlen = sizeof(struct ifla_vf_guid) },
+};
+
+static struct nla_policy sriov_stats_policy[IFLA_VF_STATS_MAX+1] = {
+ [IFLA_VF_STATS_RX_PACKETS] = { .type = NLA_U64 },
+ [IFLA_VF_STATS_TX_PACKETS] = { .type = NLA_U64 },
+ [IFLA_VF_STATS_RX_BYTES] = { .type = NLA_U64 },
+ [IFLA_VF_STATS_TX_BYTES] = { .type = NLA_U64 },
+ [IFLA_VF_STATS_BROADCAST] = { .type = NLA_U64 },
+ [IFLA_VF_STATS_MULTICAST] = { .type = NLA_U64 },
+};
+
+/** @endcond */
+
+/* Clone SRIOV VF list in link object */
+int rtnl_link_sriov_clone(struct rtnl_link *dst, struct rtnl_link *src) {
+ int err = 0;
+ struct nl_addr *vf_addr;
+ struct rtnl_link_vf *s_list, *d_vf, *s_vf, *next, *dest_h = NULL;
+ nl_vf_vlans_t *src_vlans = NULL, *dst_vlans = NULL;
+ nl_vf_vlan_info_t *src_vlan_info = NULL, *dst_vlan_info = NULL;
+
+ if (!(err = rtnl_link_has_vf_list(src)))
+ return 0;
+
+ dst->l_vf_list = rtnl_link_vf_alloc();
+ if (!dst->l_vf_list)
+ return -NLE_NOMEM;
+ dest_h = dst->l_vf_list;
+ s_list = src->l_vf_list;
+
+ nl_list_for_each_entry_safe(s_vf, next, &s_list->vf_list, vf_list) {
+ if (!(d_vf = rtnl_link_vf_alloc()))
+ return -NLE_NOMEM;
+
+ memcpy(d_vf, s_vf, sizeof(*s_vf));
+
+ if (s_vf->ce_mask & SRIOV_ATTR_ADDR) {
+ vf_addr = nl_addr_clone(s_vf->vf_lladdr);
+ if (!vf_addr) {
+ rtnl_link_vf_put(d_vf);
+ return -NLE_NOMEM;
+ }
+ d_vf->vf_lladdr = vf_addr;
+ }
+
+ if (s_vf->ce_mask & SRIOV_ATTR_VLAN) {
+ src_vlans = s_vf->vf_vlans;
+ src_vlan_info = src_vlans->vlans;
+
+ err = rtnl_link_vf_vlan_alloc(&dst_vlans,
+ src_vlans->size);
+ if (err < 0) {
+ rtnl_link_vf_put(d_vf);
+ return err;
+ }
+ dst_vlan_info = dst_vlans->vlans;
+ memcpy(dst_vlans, src_vlans, sizeof(nl_vf_vlans_t));
+ memcpy(dst_vlan_info, src_vlan_info,
+ dst_vlans->size * sizeof(dst_vlan_info));
+ d_vf->vf_vlans = dst_vlans;
+ }
+
+ nl_list_add_head(&d_vf->vf_list, &dest_h->vf_list);
+ dest_h = d_vf;
+ }
+
+ return 0;
+}
+
+/* Dump VLAN details for each SRIOV VF */
+static void dump_sriov_vlans(nl_vf_vlans_t *vlans,
+ struct nl_dump_params *p) {
+ char buf[64];
+ int cur = 0;
+ nl_vf_vlan_info_t *vlan_data;
+ uint16_t prot;
+
+ vlan_data = vlans->vlans;
+ nl_dump(p, "\t VLANS:\n");
+ while (cur < vlans->size) {
+ nl_dump(p, "\t vlan %u", vlan_data[cur].vf_vlan);
+ if (vlan_data[cur].vf_vlan_qos)
+ nl_dump(p, " qos %u", vlan_data[cur].vf_vlan_qos);
+ if (vlan_data[cur].vf_vlan_proto) {
+ prot = vlan_data[cur].vf_vlan_proto;
+ nl_dump(p, " proto %s",
+ rtnl_link_vf_vlanproto2str(prot, buf,
+ sizeof(buf)));
+ }
+ nl_dump(p, "\n");
+ cur++;
+ }
+
+ return;
+}
+
+/* Dump details for each SRIOV VF */
+static void dump_vf_details(struct rtnl_link_vf *vf_data,
+ struct nl_dump_params *p) {
+ char buf[64];
+ int err = 0;
+ struct nl_vf_rate vf_rate;
+ uint32_t v = 0;
+
+ nl_dump(p, "\tvf %u: ", vf_data->vf_index);
+ if (vf_data->ce_mask & SRIOV_ATTR_LINK_STATE) {
+ v = vf_data->vf_linkstate;
+ nl_dump(p, "state %s ",
+ rtnl_link_vf_linkstate2str(v, buf, sizeof(buf)));
+ }
+ if (vf_data->ce_mask & SRIOV_ATTR_ADDR) {
+ nl_dump(p, "addr %s ",
+ nl_addr2str(vf_data->vf_lladdr, buf, sizeof(buf)));
+ }
+ nl_dump(p, "\n");
+
+ v = vf_data->vf_spoofchk;
+ nl_dump(p, "\t spoofchk %s ", v ? SRIOVON : SRIOVOFF);
+ v = vf_data->vf_trust;
+ nl_dump(p, "trust %s ", v ? SRIOVON : SRIOVOFF);
+ v = vf_data->vf_rss_query_en;
+ nl_dump(p, "rss_query %s\n", v ? SRIOVON : SRIOVOFF);
+
+ err = rtnl_link_vf_get_rate(vf_data, &vf_rate);
+ if (!err) {
+ if (vf_rate.api == RTNL_LINK_VF_RATE_API_OLD)
+ nl_dump(p, "\t rate_api old rate %u\n",
+ vf_rate.rate);
+ else if (vf_rate.api == RTNL_LINK_VF_RATE_API_NEW)
+ nl_dump(p, "\t rate_api new min_rate %u "
+ "max_rate %u\n", vf_rate.min_tx_rate,
+ vf_rate.max_tx_rate);
+ }
+ if (vf_data->ce_mask & SRIOV_ATTR_VLAN)
+ dump_sriov_vlans(vf_data->vf_vlans, p);
+
+ return;
+}
+
+/* Loop through SRIOV VF list dump details */
+void rtnl_link_sriov_dump_details(struct rtnl_link *link,
+ struct nl_dump_params *p) {
+ int err;
+ struct rtnl_link_vf *vf_data, *list, *next;
+
+ if (!(err = rtnl_link_has_vf_list(link)))
+ BUG();
+
+ nl_dump(p, " SRIOV VF List\n");
+ list = link->l_vf_list;
+ nl_list_for_each_entry_safe(vf_data, next, &list->vf_list, vf_list) {
+ if (vf_data->ce_mask & SRIOV_ATTR_INDEX)
+ dump_vf_details(vf_data, p);
+ }
+
+ return;
+}
+
+/* Dump stats for each SRIOV VF */
+static void dump_vf_stats(struct rtnl_link_vf *vf_data,
+ struct nl_dump_params *p) {
+ char *unit;
+ float res;
+
+ nl_dump(p, " VF %" PRIu64 " Stats:\n", vf_data->vf_index);
+ nl_dump_line(p, "\tRX: %-14s %-10s %-10s %-10s\n",
+ "bytes", "packets", "multicast", "broadcast");
+
+ res = nl_cancel_down_bytes(vf_data->vf_stats[RTNL_LINK_VF_STATS_RX_BYTES],
+ &unit);
+
+ nl_dump_line(p,
+ "\t%10.2f %3s %10" PRIu64 " %10" PRIu64 " %10" PRIu64 "\n",
+ res, unit,
+ vf_data->vf_stats[RTNL_LINK_VF_STATS_RX_PACKETS],
+ vf_data->vf_stats[RTNL_LINK_VF_STATS_MULTICAST],
+ vf_data->vf_stats[RTNL_LINK_VF_STATS_BROADCAST]);
+
+ nl_dump_line(p, "\tTX: %-14s %-10s\n", "bytes", "packets");
+
+ res = nl_cancel_down_bytes(vf_data->vf_stats[RTNL_LINK_VF_STATS_TX_BYTES],
+ &unit);
+
+ nl_dump_line(p, "\t%10.2f %3s %10" PRIu64 "\n", res, unit,
+ vf_data->vf_stats[RTNL_LINK_VF_STATS_TX_PACKETS]);
+
+ return;
+}
+
+/* Loop through SRIOV VF list dump stats */
+void rtnl_link_sriov_dump_stats(struct rtnl_link *link,
+ struct nl_dump_params *p) {
+ struct rtnl_link_vf *vf_data, *list, *next;
+
+ list = link->l_vf_list;
+ nl_list_for_each_entry_safe(vf_data, next, &list->vf_list, vf_list) {
+ if (vf_data->ce_mask & SRIOV_ATTR_INDEX)
+ dump_vf_stats(vf_data, p);
+ }
+ nl_dump(p, "\n");
+
+ return;
+}
+
+/* Free stored SRIOV VF data */
+void rtnl_link_sriov_free_data(struct rtnl_link *link) {
+ int err = 0;
+ struct rtnl_link_vf *list, *vf, *next;
+
+ if (!(err = rtnl_link_has_vf_list(link)))
+ return;
+
+ list = link->l_vf_list;
+ nl_list_for_each_entry_safe(vf, next, &list->vf_list, vf_list) {
+ nl_list_del(&vf->vf_list);
+ rtnl_link_vf_put(vf);
+ }
+
+ rtnl_link_vf_put(link->l_vf_list);
+
+ return;
+}
+
+/* Fill VLAN info array */
+static int rtnl_link_vf_vlan_info(int len, struct ifla_vf_vlan_info **vi,
+ nl_vf_vlans_t **nvi) {
+ int cur = 0, err;
+ nl_vf_vlans_t *vlans;
+
+ if (len <= 0)
+ return 0;
+
+ if ((err = rtnl_link_vf_vlan_alloc(&vlans, len)) < 0)
+ return err;
+
+ cur = 0;
+ while (cur < len) {
+ vlans->vlans[cur].vf_vlan = vi[cur]->vlan ? vi[cur]->vlan : 0;
+ vlans->vlans[cur].vf_vlan_qos = vi[cur]->qos ? vi[cur]->qos : 0;
+ if (vi[cur]->vlan_proto) {
+ vlans->vlans[cur].vf_vlan_proto = ntohs(vi[cur]->vlan_proto);
+ } else {
+ vlans->vlans[cur].vf_vlan_proto = ETH_P_8021Q;
+ }
+ cur++;
+ }
+
+ *nvi = vlans;
+ return 0;
+}
+
+/* Fill the IFLA_VF_VLAN attribute */
+static void sriov_fill_vf_vlan(struct nl_msg *msg, nl_vf_vlan_info_t *vinfo,
+ uint32_t index) {
+ struct ifla_vf_vlan vlan;
+
+ vlan.vf = index;
+ vlan.vlan = vinfo[0].vf_vlan;
+ vlan.qos = vinfo[0].vf_vlan_qos;
+ NLA_PUT(msg, IFLA_VF_VLAN, sizeof(vlan), &vlan);
+
+nla_put_failure:
+ return;
+}
+
+/* Fill the IFLA_VF_VLAN_LIST attribute */
+static int sriov_fill_vf_vlan_list(struct nl_msg *msg, nl_vf_vlans_t *vlans,
+ uint32_t index) {
+ int cur = 0;
+ nl_vf_vlan_info_t *vlan_info = vlans->vlans;
+ struct ifla_vf_vlan_info vlan;
+ struct nlattr *list;
+
+ if (!(list = nla_nest_start(msg, IFLA_VF_VLAN_LIST)))
+ return -NLE_MSGSIZE;
+
+ vlan.vf = index;
+ while (cur < vlans->size) {
+ vlan.vlan = vlan_info[cur].vf_vlan;
+ vlan.qos = vlan_info[cur].vf_vlan_qos;
+ vlan.vlan_proto = vlan_info[cur].vf_vlan_proto;
+
+ NLA_PUT(msg, IFLA_VF_VLAN_INFO, sizeof(vlan), &vlan);
+
+ cur++;
+ }
+
+nla_put_failure:
+ nla_nest_end(msg, list);
+
+ return 0;
+}
+
+/* Fill individual IFLA_VF_INFO attributes */
+static int sriov_fill_vfinfo(struct nl_msg *msg,
+ struct rtnl_link_vf *vf_data) {
+ int err = 0, new_rate = 0;
+ nl_vf_vlans_t *vlan_list;
+ nl_vf_vlan_info_t *vlan_info;
+ struct ifla_vf_guid vf_node_guid;
+ struct ifla_vf_guid vf_port_guid;
+ struct ifla_vf_link_state vf_link_state;
+ struct ifla_vf_mac vf_mac;
+ struct ifla_vf_rate new_vf_rate;
+ struct ifla_vf_rss_query_en vf_rss_query_en;
+ struct ifla_vf_spoofchk vf_spoofchk;
+ struct ifla_vf_trust vf_trust;
+ struct ifla_vf_tx_rate vf_rate;
+ struct nlattr *list;
+ uint16_t proto;
+
+ if (!(vf_data->ce_mask & SRIOV_ATTR_INDEX))
+ return -NLE_MISSING_ATTR;
+
+ if (!(list = nla_nest_start(msg, IFLA_VF_INFO)))
+ return -NLE_MSGSIZE;
+
+ /* IFLA_VF_MAC */
+ if (vf_data->ce_mask & SRIOV_ATTR_ADDR) {
+ vf_mac.vf = vf_data->vf_index;
+ memset(vf_mac.mac, 0, sizeof(vf_mac.mac));
+ memcpy(vf_mac.mac, nl_addr_get_binary_addr(vf_data->vf_lladdr),
+ nl_addr_get_len(vf_data->vf_lladdr));
+ NLA_PUT(msg, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac);
+ }
+
+ /* IFLA_VF_VLAN IFLA_VF_VLAN_LIST */
+ if (vf_data->ce_mask & SRIOV_ATTR_VLAN) {
+ vlan_list = vf_data->vf_vlans;
+ vlan_info = vlan_list->vlans;
+ proto = vlan_info[0].vf_vlan_proto;
+ if (!proto)
+ proto = ETH_P_8021Q;
+
+ if ((vlan_list->size == 1) && (proto == ETH_P_8021Q))
+ sriov_fill_vf_vlan(msg, vlan_info, vf_data->vf_index);
+ else
+ err = sriov_fill_vf_vlan_list(msg, vlan_list,
+ vf_data->vf_index);
+ }
+
+ /* IFLA_VF_TX_RATE */
+ if (vf_data->ce_mask & SRIOV_ATTR_TX_RATE) {
+ vf_rate.vf = vf_data->vf_index;
+ vf_rate.rate = vf_data->vf_rate;
+
+ NLA_PUT(msg, IFLA_VF_TX_RATE, sizeof(vf_rate), &vf_rate);
+ }
+
+ /* IFLA_VF_RATE */
+ new_vf_rate.min_tx_rate = 0;
+ new_vf_rate.max_tx_rate = 0;
+ new_vf_rate.vf = vf_data->vf_index;
+ if (vf_data->ce_mask & SRIOV_ATTR_RATE_MIN) {
+ new_vf_rate.min_tx_rate = vf_data->vf_min_tx_rate;
+ new_rate = 1;
+ }
+ if (vf_data->ce_mask & SRIOV_ATTR_RATE_MAX) {
+ new_vf_rate.max_tx_rate = vf_data->vf_max_tx_rate;
+ new_rate = 1;
+ }
+ if (new_rate)
+ NLA_PUT(msg, IFLA_VF_RATE, sizeof(new_vf_rate), &new_vf_rate);
+
+ /* IFLA_VF_SPOOFCHK */
+ if (vf_data->ce_mask & SRIOV_ATTR_SPOOFCHK) {
+ vf_spoofchk.vf = vf_data->vf_index;
+ vf_spoofchk.setting = vf_data->vf_spoofchk;
+
+ NLA_PUT(msg, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk),
+ &vf_spoofchk);
+ }
+
+ /* IFLA_VF_LINK_STATE */
+ if (vf_data->ce_mask & SRIOV_ATTR_LINK_STATE) {
+ vf_link_state.vf = vf_data->vf_index;
+ vf_link_state.link_state = vf_data->vf_linkstate;
+
+ NLA_PUT(msg, IFLA_VF_LINK_STATE, sizeof(vf_link_state),
+ &vf_link_state);
+ }
+
+ /* IFLA_VF_RSS_QUERY_EN */
+ if (vf_data->ce_mask & SRIOV_ATTR_RSS_QUERY_EN) {
+ vf_rss_query_en.vf = vf_data->vf_index;
+ vf_rss_query_en.setting = vf_data->vf_rss_query_en;
+
+ NLA_PUT(msg, IFLA_VF_RSS_QUERY_EN, sizeof(vf_rss_query_en),
+ &vf_rss_query_en);
+ }
+
+ /* IFLA_VF_TRUST */
+ if (vf_data->ce_mask & SRIOV_ATTR_TRUST) {
+ vf_trust.vf = vf_data->vf_index;
+ vf_trust.setting = vf_data->vf_trust;
+
+ NLA_PUT(msg, IFLA_VF_TRUST, sizeof(vf_trust), &vf_trust);
+ }
+
+ /* IFLA_VF_IB_NODE_GUID */
+ if (vf_data->ce_mask & SRIOV_ATTR_IB_NODE_GUID) {
+ vf_node_guid.vf = vf_data->vf_index;
+ vf_node_guid.guid = vf_data->vf_guid_node;
+
+ NLA_PUT(msg, IFLA_VF_IB_NODE_GUID, sizeof(vf_node_guid),
+ &vf_node_guid);
+ }
+
+ /* IFLA_VF_IB_PORT_GUID */
+ if (vf_data->ce_mask & SRIOV_ATTR_IB_PORT_GUID) {
+ vf_port_guid.vf = vf_data->vf_index;
+ vf_port_guid.guid = vf_data->vf_guid_port;
+
+ NLA_PUT(msg, IFLA_VF_IB_PORT_GUID, sizeof(vf_port_guid),
+ &vf_port_guid);
+ }
+
+nla_put_failure:
+ nla_nest_end(msg, list);
+
+ return err;
+}
+
+/* Fill the IFLA_VFINFO_LIST attribute */
+int rtnl_link_sriov_fill_vflist(struct nl_msg *msg, struct rtnl_link *link) {
+ int err = 0;
+ struct nlattr *data;
+ struct rtnl_link_vf *list, *vf, *next;
+
+ if (!(err = rtnl_link_has_vf_list(link)))
+ return 0;
+
+ if (!(data = nla_nest_start(msg, IFLA_VFINFO_LIST)))
+ return -NLE_MSGSIZE;
+
+ list = link->l_vf_list;
+ nl_list_for_each_entry_safe(vf, next, &list->vf_list, vf_list) {
+ if (vf->ce_mask & SRIOV_ATTR_INDEX) {
+ if ((err = sriov_fill_vfinfo(msg, vf)) < 0)
+ goto nla_nest_list_failure;
+ }
+ }
+
+nla_nest_list_failure:
+ nla_nest_end(msg, data);
+
+ return err;
+}
+
+/* Parse IFLA_VFINFO_LIST and IFLA_VF_INFO attributes */
+int rtnl_link_sriov_parse_vflist(struct rtnl_link *link, struct nlattr **tb) {
+ int err, len, list_len, list_rem;
+ struct ifla_vf_mac *vf_lladdr;
+ struct ifla_vf_vlan *vf_vlan;
+ struct ifla_vf_vlan_info *vf_vlan_info[MAX_VLAN_LIST_LEN];
+ struct ifla_vf_tx_rate *vf_tx_rate;
+ struct ifla_vf_spoofchk *vf_spoofchk;
+ struct ifla_vf_link_state *vf_linkstate;
+ struct ifla_vf_rate *vf_rate;
+ struct ifla_vf_rss_query_en *vf_rss_query;
+ struct ifla_vf_trust *vf_trust;
+ struct nlattr *nla, *nla_list, *t[IFLA_VF_MAX+1],
+ *stb[RTNL_LINK_VF_STATS_MAX+1];
+ nl_vf_vlans_t *vf_vlans = NULL;
+ struct rtnl_link_vf *vf_data, *vf_head = NULL;
+
+ len = nla_len(tb[IFLA_VFINFO_LIST]);
+ link->l_vf_list = rtnl_link_vf_alloc();
+ if (!link->l_vf_list)
+ return -NLE_NOMEM;
+ vf_head = link->l_vf_list;
+
+ for (nla = nla_data(tb[IFLA_VFINFO_LIST]); nla_ok(nla, len);
+ nla = nla_next(nla, &len)) {
+ err = nla_parse(t, IFLA_VF_MAX, nla_data(nla), nla_len(nla),
+ sriov_info_policy);
+ if (err < 0)
+ return err;
+
+ vf_data = rtnl_link_vf_alloc();
+ if (!vf_data)
+ return -NLE_NOMEM;
+
+ if (t[IFLA_VF_MAC]) {
+ vf_lladdr = nla_data(t[IFLA_VF_MAC]);
+
+ vf_data->vf_index = vf_lladdr->vf;
+ vf_data->ce_mask |= SRIOV_ATTR_INDEX;
+
+ vf_data->vf_lladdr = nl_addr_build(AF_LLC,
+ vf_lladdr->mac, 6);
+ if (vf_data->vf_lladdr == NULL) {
+ rtnl_link_vf_put(vf_data);
+ return -NLE_NOMEM;
+ }
+ nl_addr_set_family(vf_data->vf_lladdr, AF_LLC);
+ vf_data->ce_mask |= SRIOV_ATTR_ADDR;
+ }
+
+ if (t[IFLA_VF_VLAN_LIST]) {
+ list_len = 0;
+ nla_for_each_nested(nla_list, t[IFLA_VF_VLAN_LIST],
+ list_rem) {
+ if (list_len >= MAX_VLAN_LIST_LEN)
+ break;
+ vf_vlan_info[list_len] = nla_data(nla_list);
+ list_len++;
+ }
+
+ err = rtnl_link_vf_vlan_info(list_len, vf_vlan_info,
+ &vf_vlans);
+ if (err < 0) {
+ rtnl_link_vf_put(vf_data);
+ return err;
+ }
+
+ vf_data->vf_vlans = vf_vlans;
+ vf_data->ce_mask |= SRIOV_ATTR_VLAN;
+ } else if (t[IFLA_VF_VLAN]) {
+ vf_vlan = nla_data(t[IFLA_VF_VLAN]);
+
+ if (vf_vlan->vlan) {
+ err = rtnl_link_vf_vlan_alloc(&vf_vlans, 1);
+ if (err < 0) {
+ rtnl_link_vf_put(vf_data);
+ return err;
+ }
+
+ vf_vlans->vlans[0].vf_vlan = vf_vlan->vlan;
+ vf_vlans->vlans[0].vf_vlan_qos = vf_vlan->qos;
+ vf_vlans->vlans[0].vf_vlan_proto = ETH_P_8021Q;
+
+ vf_data->vf_vlans = vf_vlans;
+ vf_data->ce_mask |= SRIOV_ATTR_VLAN;
+ }
+ }
+
+ if (t[IFLA_VF_TX_RATE]) {
+ vf_tx_rate = nla_data(t[IFLA_VF_TX_RATE]);
+
+ if (vf_tx_rate->rate) {
+ vf_data->vf_rate = vf_tx_rate->rate;
+ vf_data->ce_mask |= SRIOV_ATTR_TX_RATE;
+ }
+ }
+
+ if (t[IFLA_VF_SPOOFCHK]) {
+ vf_spoofchk = nla_data(t[IFLA_VF_SPOOFCHK]);
+
+ if (vf_spoofchk->setting != -1) {
+ vf_data->vf_spoofchk = vf_spoofchk->setting ? 1 : 0;
+ vf_data->ce_mask |= SRIOV_ATTR_SPOOFCHK;
+ }
+ }
+
+ if (t[IFLA_VF_LINK_STATE]) {
+ vf_linkstate = nla_data(t[IFLA_VF_LINK_STATE]);
+
+ vf_data->vf_linkstate = vf_linkstate->link_state;
+ vf_data->ce_mask |= SRIOV_ATTR_LINK_STATE;
+ }
+
+ if (t[IFLA_VF_RATE]) {
+ vf_rate = nla_data(t[IFLA_VF_RATE]);
+
+ if (vf_rate->max_tx_rate) {
+ vf_data->vf_max_tx_rate = vf_rate->max_tx_rate;
+ vf_data->ce_mask |= SRIOV_ATTR_RATE_MAX;
+ }
+ if (vf_rate->min_tx_rate) {
+ vf_data->vf_min_tx_rate = vf_rate->min_tx_rate;
+ vf_data->ce_mask |= SRIOV_ATTR_RATE_MIN;
+ }
+ }
+
+ if (t[IFLA_VF_RSS_QUERY_EN]) {
+ vf_rss_query = nla_data(t[IFLA_VF_RSS_QUERY_EN]);
+
+ if (vf_rss_query->setting != -1) {
+ vf_data->vf_rss_query_en = vf_rss_query->setting ? 1 : 0;
+ vf_data->ce_mask |= SRIOV_ATTR_RSS_QUERY_EN;
+ }
+ }
+
+ if (t[IFLA_VF_STATS]) {
+ err = nla_parse_nested(stb, IFLA_VF_STATS_MAX,
+ t[IFLA_VF_STATS],
+ sriov_stats_policy);
+ if (err < 0) {
+ rtnl_link_vf_put(vf_data);
+ return err;
+ }
+
+ SET_VF_STAT(link, cur, stb,
+ RTNL_LINK_VF_STATS_RX_PACKETS,
+ IFLA_VF_STATS_RX_PACKETS);
+ SET_VF_STAT(link, cur, stb,
+ RTNL_LINK_VF_STATS_TX_PACKETS,
+ IFLA_VF_STATS_TX_PACKETS);
+ SET_VF_STAT(link, cur, stb,
+ RTNL_LINK_VF_STATS_RX_BYTES,
+ IFLA_VF_STATS_RX_BYTES);
+ SET_VF_STAT(link, cur, stb,
+ RTNL_LINK_VF_STATS_TX_BYTES,
+ IFLA_VF_STATS_TX_BYTES);
+ SET_VF_STAT(link, cur, stb,
+ RTNL_LINK_VF_STATS_BROADCAST,
+ IFLA_VF_STATS_BROADCAST);
+ SET_VF_STAT(link, cur, stb,
+ RTNL_LINK_VF_STATS_MULTICAST,
+ IFLA_VF_STATS_MULTICAST);
+
+ vf_data->ce_mask |= IFLA_VF_STATS;
+ }
+
+ if (t[IFLA_VF_TRUST]) {
+ vf_trust = nla_data(t[IFLA_VF_TRUST]);
+
+ if (vf_trust->setting != -1) {
+ vf_data->vf_trust = vf_trust->setting ? 1 : 0;
+ vf_data->ce_mask |= SRIOV_ATTR_TRUST;
+ }
+ }
+
+ nl_list_add_head(&vf_data->vf_list, &vf_head->vf_list);
+ vf_head = vf_data;
+ }
+
+ return 0;
+}
+
+/**
+ * @name SR-IOV Sub-Object
+ * @{
+ */
+
+/**
+ * Add a SRIOV VF object to a link object
+ * @param link Link object to add to
+ * @param vf_data SRIOV VF object to add
+ *
+ * @return 0 if SRIOV VF object added successfully
+ * @return -NLE_OBJ_NOTFOUND if \p link or \p vf_data not provided
+ * @return -NLE_NOMEM if out of memory
+ */
+int rtnl_link_vf_add(struct rtnl_link *link, struct rtnl_link_vf *vf_data) {
+ struct rtnl_link_vf *vf_head = NULL;
+
+ if (!link||!vf_data)
+ return -NLE_OBJ_NOTFOUND;
+
+ if (!link->l_vf_list) {
+ link->l_vf_list = rtnl_link_vf_alloc();
+ if (!link->l_vf_list)
+ return -NLE_NOMEM;
+ }
+
+ vf_head = vf_data;
+ vf_head->ce_refcnt++;
+
+ vf_head = link->l_vf_list;
+ nl_list_add_head(&vf_data->vf_list, &vf_head->vf_list);
+ link->l_vf_list = vf_head;
+
+ rtnl_link_set_vf_list(link);
+
+ return 0;
+}
+
+/**
+ * Allocate a new SRIOV VF object
+ *
+ * @return NULL if out of memory
+ * @return New VF Object
+ *
+ * @see rtnl_link_vf_put()
+ *
+ * The SRIOV VF object must be returned to the link object with
+ * rtnl_link_vf_put() when operations are done to prevent memory leaks.
+ */
+struct rtnl_link_vf *rtnl_link_vf_alloc(void) {
+ struct rtnl_link_vf *vf;
+
+ if (!(vf = calloc(1, sizeof(*vf))))
+ return NULL;
+
+ NL_INIT_LIST_HEAD(&vf->vf_list);
+ vf->ce_refcnt = 1;
+
+ NL_DBG(4, "Allocated new SRIOV VF object %p\n", vf);
+
+ return vf;
+}
+
+/**
+ * Free SRIOV VF object.
+ * @arg vf_data SRIOV VF data object
+ */
+void rtnl_link_vf_free(struct rtnl_link_vf *vf_data) {
+ if (!vf_data)
+ return;
+
+ if (vf_data->ce_refcnt > 0)
+ NL_DBG(1, "Warning: Freeing SRIOV VF object in use...\n");
+
+ if (vf_data->ce_mask & SRIOV_ATTR_ADDR)
+ nl_addr_put(vf_data->vf_lladdr);
+ if (vf_data->ce_mask & SRIOV_ATTR_VLAN)
+ rtnl_link_vf_vlan_put(vf_data->vf_vlans);
+
+ NL_DBG(4, "Freed SRIOV VF object %p\n", vf_data);
+ free(vf_data);
+
+ return;
+}
+
+/**
+ * Lookup SRIOV VF in link object by VF index.
+ *
+ * @return NULL if VF not found
+ * @return VF Object
+ *
+ * @see rtnl_link_vf_put()
+ *
+ * The SRIOV VF object must be returned to the link object with
+ * rtnl_link_vf_put() when operations are done to prevent memory leaks.
+ */
+struct rtnl_link_vf *rtnl_link_vf_get(struct rtnl_link *link, uint32_t vf_num) {
+ struct rtnl_link_vf *list, *vf, *next, *ret = NULL;
+
+ list = link->l_vf_list;
+ nl_list_for_each_entry_safe(vf, next, &list->vf_list, vf_list) {
+ if (vf->vf_index == vf_num) {
+ ret = vf;
+ break;
+ }
+ }
+
+ if (ret) {
+ ret->ce_refcnt++;
+ NL_DBG(4, "New reference to SRIOV VF object %p, total %i\n",
+ ret, ret->ce_refcnt);
+ }
+
+ return ret;
+}
+
+/**
+ * Return SRIOV VF object to the owning link object.
+ * @arg vf_data SRIOV VF data object
+ *
+ * @see rtnl_link_vf_alloc()
+ * @see rtnl_link_vf_get()
+ */
+void rtnl_link_vf_put(struct rtnl_link_vf *vf_data) {
+ if (!vf_data)
+ return;
+
+ vf_data->ce_refcnt--;
+ NL_DBG(4, "Returned SRIOV VF object reference %p, %i remaining\n",
+ vf_data, vf_data->ce_refcnt);
+
+ if (vf_data->ce_refcnt < 0)
+ BUG();
+
+ if (vf_data->ce_refcnt <= 0)
+ rtnl_link_vf_free(vf_data);
+
+ return;
+}
+
+/**
+ * Get link layer address of SRIOV Virtual Function
+ * @arg vf_data SRIOV VF object
+ * @arg addr Pointer to store Link Layer address
+ *
+ * @see rtnl_link_get_num_vf()
+ * @see rtnl_link_vf_set_addr()
+ *
+ * @copydoc pointer_lifetime_warning
+ * @return 0 if addr is present and addr is set to pointer containing address
+ * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
+ * @return -NLE_NOATTR if the link layer address is not set
+ */
+int rtnl_link_vf_get_addr(struct rtnl_link_vf *vf_data, struct nl_addr **addr)
+{
+ if (!vf_data)
+ return -NLE_OBJ_NOTFOUND;
+
+ if (vf_data->ce_mask & SRIOV_ATTR_ADDR)
+ *addr = vf_data->vf_lladdr;
+ else
+ return -NLE_NOATTR;
+
+ return 0;
+}
+
+/**
+ * Set link layer address of SRIOV Virtual Function object
+ * @param vf_data SRIOV VF object
+ * @param addr New link layer address
+ *
+ * This function increments the reference counter of the address object
+ * and overwrites any existing link layer address previously assigned.
+ *
+ * @see rtnl_link_vf_get_addr()
+ */
+void rtnl_link_vf_set_addr(struct rtnl_link_vf *vf_data, struct nl_addr *addr) {
+ if (vf_data->vf_lladdr)
+ nl_addr_put(vf_data->vf_lladdr);
+
+ nl_addr_get(addr);
+ vf_data->vf_lladdr = addr;
+ vf_data->ce_mask |= SRIOV_ATTR_ADDR;
+
+ return;
+}
+
+/**
+ * Set the Infiniband node GUID for the SRIOV Virtual Function object
+ * @param vf_data SRIOV VF object
+ * @param guid node GUID
+ */
+void rtnl_link_vf_set_ib_node_guid(struct rtnl_link_vf *vf_data,
+ uint64_t guid) {
+ vf_data->vf_guid_node = guid;
+ vf_data->ce_mask |= SRIOV_ATTR_IB_NODE_GUID;
+
+ return;
+}
+
+/**
+ * Set the Infiniband port GUID for the SRIOV Virtual Function object
+ * @param vf_data SRIOV VF object
+ * @param guid port GUID
+ */
+void rtnl_link_vf_set_ib_port_guid(struct rtnl_link_vf *vf_data,
+ uint64_t guid) {
+ vf_data->vf_guid_port = guid;
+ vf_data->ce_mask |= SRIOV_ATTR_IB_PORT_GUID;
+
+ return;
+}
+
+/**
+ * Get index of SRIOV Virtual Function
+ * @arg vf_data SRIOV VF object
+ * @arg vf_index Pointer to store VF index
+ *
+ * @see rtnl_link_get_num_vf()
+ *
+ * @return 0 if index is present and vf_index is set
+ * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
+ * @return -NLE_NOATTR if the VF index is not set
+ */
+int rtnl_link_vf_get_index(struct rtnl_link_vf *vf_data, uint32_t *vf_index)
+{
+ if (!vf_data)
+ return -NLE_OBJ_NOTFOUND;
+
+ if (vf_data->ce_mask & SRIOV_ATTR_INDEX)
+ *vf_index = vf_data->vf_index;
+ else
+ return -NLE_NOATTR;
+
+ return 0;
+}
+
+/**
+ * Set index of SRIOV Virtual Function object
+ * @param vf_data SRIOV VF object
+ * @param vf_index Index value
+ *
+ * @see rtnl_link_vf_get_index()
+ */
+void rtnl_link_vf_set_index(struct rtnl_link_vf *vf_data, uint32_t vf_index)
+{
+ vf_data->vf_index = vf_index;
+ vf_data->ce_mask |= SRIOV_ATTR_INDEX;
+
+ return;
+}
+
+/**
+ * Get link state of SRIOV Virtual Function
+ * @arg vf_data SRIOV VF object
+ * @arg vf_linkstate Pointer to store VF link state
+ *
+ * @see rtnl_link_get_num_vf()
+ * @see rtnl_link_set_linkstate()
+ *
+ * @return 0 if link state is present and vf_linkstate is set
+ * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
+ * @return -NLE_NOATTR if the VF link state is not set
+ */
+int rtnl_link_vf_get_linkstate(struct rtnl_link_vf *vf_data,
+ uint32_t *vf_linkstate)
+{
+ if (!vf_data)
+ return -NLE_OBJ_NOTFOUND;
+
+ if (vf_data->ce_mask & SRIOV_ATTR_LINK_STATE)
+ *vf_linkstate = vf_data->vf_linkstate;
+ else
+ return -NLE_NOATTR;
+
+ return 0;
+}
+
+/**
+ * Set link state of SRIOV Virtual Function object
+ * @param vf_data SRIOV VF object
+ * @param vf_linkstate Link state value
+ *
+ * @see rtnl_link_get_linkstate()
+ *
+ * Not all hardware supports setting link state. If the feature is unsupported,
+ * the link change request will fail with -NLE_OPNOTSUPP
+ */
+void rtnl_link_vf_set_linkstate(struct rtnl_link_vf *vf_data,
+ uint32_t vf_linkstate) {
+ vf_data->vf_linkstate = vf_linkstate;
+ vf_data->ce_mask |= SRIOV_ATTR_LINK_STATE;
+
+ return;
+}
+
+/**
+ * Get TX Rate Limit of SRIOV Virtual Function
+ * @arg vf_data SRIOV VF object
+ * @arg vf_rate Pointer to store VF rate limiting data
+ *
+ * @see rtnl_link_get_num_vf()
+ * @see rtnl_link_set_rate()
+ *
+ * When the older rate API has been implemented, the rate member of the struct
+ * will be set, and the api member will be set to RTNL_LINK_VF_API_OLD.
+ * When the newer rate API has been implemented, the max_tx_rate
+ * and/or the minx_tx_rate will be set, and the api member will be set to
+ * RTNL_LINK_VF_API_NEW.
+ *
+ * Old rate API supports only a maximum TX rate.
+ * ip link set dev vf 0 rate
+ * New rate API supports minumum and maximum TX rates.
+ * ip link set dev vf 0 min_tx_rate
+ * ip link set dev vf 0 max_tx_rate
+ *
+ * @return 0 if rate is present and vf_rate is set
+ * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
+ * @return -NLE_NOATTR if the VF rate is not set
+ */
+int rtnl_link_vf_get_rate(struct rtnl_link_vf *vf_data,
+ struct nl_vf_rate *vf_rate)
+{
+ int set = 0;
+
+ if (!vf_data)
+ return -NLE_OBJ_NOTFOUND;
+
+ vf_rate->api = RTNL_LINK_VF_RATE_API_UNSPEC;
+ vf_rate->rate = 0;
+ vf_rate->max_tx_rate = 0;
+ vf_rate->min_tx_rate = 0;
+
+ if (vf_data->ce_mask & SRIOV_ATTR_RATE_MAX) {
+ if (vf_data->vf_max_tx_rate) {
+ vf_rate->api = RTNL_LINK_VF_RATE_API_NEW;
+ vf_rate->max_tx_rate = vf_data->vf_max_tx_rate;
+ set = 1;
+ }
+ }
+ if (vf_data->ce_mask & SRIOV_ATTR_RATE_MIN) {
+ if (vf_data->vf_min_tx_rate) {
+ vf_rate->api = RTNL_LINK_VF_RATE_API_NEW;
+ vf_rate->min_tx_rate = vf_data->vf_min_tx_rate;
+ set = 1;
+ }
+ }
+ if ((!set) && (vf_data->ce_mask & SRIOV_ATTR_TX_RATE)) {
+ if (vf_data->vf_rate) {
+ vf_rate->api = RTNL_LINK_VF_RATE_API_OLD;
+ vf_rate->rate = vf_data->vf_rate;
+ set = 1;
+ }
+ }
+
+ if (!set)
+ return -NLE_NOATTR;
+
+ return 0;
+}
+
+/**
+ * Set TX Rate Limit of SRIOV Virtual Function object
+ * @param vf_data SRIOV VF object
+ * @param vf_rate Rate limiting structure
+ *
+ * @see rtnl_link_vf_get_rate()
+ *
+ * When setting the rate, the API level must be specificed.
+ * Valid API levels:
+ * RTNL_LINK_VF_RATE_API_NEW
+ * RTNL_LINK_VF_RATE_API_OLD
+ *
+ * When using the new API, if either the min_tx_rate or
+ * max_tx_rate has been set, and the other is being changed,
+ * you must specify the currently set values to preserve
+ * them. If this is not done, that setting will be disabled.
+ *
+ * Old rate API supports only a maximum TX rate.
+ * ip link set dev vf 0 rate
+ * New rate API supports minumum and maximum TX rates.
+ * ip link set dev vf 0 min_tx_rate
+ * ip link set dev vf 0 max_tx_rate
+ *
+ * Not all hardware supports min_tx_rate.
+ */
+void rtnl_link_vf_set_rate(struct rtnl_link_vf *vf_data,
+ struct nl_vf_rate *vf_rate) {
+ if (vf_rate->api == RTNL_LINK_VF_RATE_API_OLD) {
+ vf_data->vf_rate = vf_rate->rate;
+ vf_data->ce_mask |= SRIOV_ATTR_TX_RATE;
+ } else if (vf_rate->api == RTNL_LINK_VF_RATE_API_NEW) {
+ vf_data->vf_max_tx_rate = vf_rate->max_tx_rate;
+ vf_data->ce_mask |= SRIOV_ATTR_RATE_MAX;
+
+ vf_data->vf_min_tx_rate = vf_rate->min_tx_rate;
+ vf_data->ce_mask |= SRIOV_ATTR_RATE_MIN;
+ }
+
+ return;
+}
+
+/**
+ * Get RSS Query EN value of SRIOV Virtual Function
+ * @arg vf_data SRIOV VF object
+ * @arg vf_rss_query_en Pointer to store VF RSS Query value
+ *
+ * @see rtnl_link_get_num_vf()
+ * @see rtnl_link_vf_set_rss_query_en()
+ *
+ * @return 0 if rss_query_en is present and vf_rss_query_en is set
+ * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
+ * @return -NLE_NOATTR if the VF RSS Query EN value is not set
+ */
+int rtnl_link_vf_get_rss_query_en(struct rtnl_link_vf *vf_data,
+ uint32_t *vf_rss_query_en)
+{
+ if (!vf_data)
+ return -NLE_OBJ_NOTFOUND;
+
+ if (vf_data->ce_mask & SRIOV_ATTR_RSS_QUERY_EN)
+ *vf_rss_query_en = vf_data->vf_rss_query_en;
+ else
+ return -NLE_NOATTR;
+
+ return 0;
+}
+
+/**
+ * Set RSS configuration querying of SRIOV Virtual Function Object
+ * @arg vf_data SRIOV VF object
+ * @arg vf_rss_query_en RSS Query value
+ *
+ * @see rtnl_link_vf_get_rss_query_en()
+ */
+void rtnl_link_vf_set_rss_query_en(struct rtnl_link_vf *vf_data,
+ uint32_t vf_rss_query_en) {
+ vf_data->vf_rss_query_en = vf_rss_query_en;
+ vf_data->ce_mask |= SRIOV_ATTR_RSS_QUERY_EN;
+
+ return;
+}
+
+/**
+ * Get spoof checking value of SRIOV Virtual Function
+ * @arg vf_data SRIOV VF object
+ * @arg vf_spoofchk Pointer to store VF spoofchk value
+ *
+ * @see rtnl_link_get_num_vf()
+ * @see rtnl_link_set_spoofchk()
+ *
+ * @return 0 if spoofchk is present and vf_spoofchk is set
+ * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
+ * @return -NLE_NOATTR if the VF spoofcheck is not set
+ */
+int rtnl_link_vf_get_spoofchk(struct rtnl_link_vf *vf_data,
+ uint32_t *vf_spoofchk)
+{
+ if (!vf_data)
+ return -NLE_OBJ_NOTFOUND;
+
+ if (vf_data->ce_mask & SRIOV_ATTR_SPOOFCHK)
+ *vf_spoofchk = vf_data->vf_spoofchk;
+ else
+ return -NLE_NOATTR;
+
+ return 0;
+}
+
+/**
+ * Set spoof checking value of SRIOV Virtual Function Object
+ * @param vf_data
+ * @param vf_spoofchk
+ *
+ * @see rtnl_link_vf_get_spoofchk()
+ */
+void rtnl_link_vf_set_spoofchk(struct rtnl_link_vf *vf_data,
+ uint32_t vf_spoofchk) {
+ vf_data->vf_spoofchk = vf_spoofchk;
+ vf_data->ce_mask |= SRIOV_ATTR_SPOOFCHK;
+
+ return;
+}
+
+/**
+ * Get value of stat counter for SRIOV Virtual Function
+ * @arg vf_data SRIOV VF object
+ * @arg stat Identifier of statistical counter
+ * @arg vf_stat Pointer to store VF stat value in
+ *
+ * @see rtnl_link_get_num_vf()
+ *
+ * @return 0 if stat is present and vf_stat is set
+ * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
+ * @return -NLE_NOATTR if the VF stat is not set
+ */
+int rtnl_link_vf_get_stat(struct rtnl_link_vf *vf_data,
+ rtnl_link_vf_stats_t stat, uint64_t *vf_stat)
+{
+ if (!vf_data)
+ return -NLE_OBJ_NOTFOUND;
+
+ if (vf_data->ce_mask & SRIOV_ATTR_STATS)
+ *vf_stat = vf_data->vf_stats[stat];
+ else
+ return -NLE_NOATTR;
+
+ return 0;
+}
+
+/**
+ * Get trust setting of SRIOV Virtual Function
+ * @arg vf_data SRIOV VF object
+ * @arg vf_trust Pointer to store VF trust value
+ *
+ * @see rtnl_link_get_num_vf()
+ * @see rtnl_link_set_trust()
+ *
+ * @return 0 if trust is present and vf_trust is set
+ * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
+ * @return -NLE_NOATTR if the VF trust setting is not set
+ */
+int rtnl_link_vf_get_trust(struct rtnl_link_vf *vf_data, uint32_t *vf_trust)
+{
+ if (!vf_data)
+ return -NLE_OBJ_NOTFOUND;
+
+ if (vf_data->ce_mask & SRIOV_ATTR_TRUST)
+ *vf_trust = vf_data->vf_trust;
+ else
+ return -NLE_NOATTR;
+
+ return 0;
+}
+
+/**
+ * Set user trust setting on SRIOV Virtual Function Object
+ * @param vf_data
+ * @param vf_trust
+ *
+ * @see rtnl_link_vf_get_trust()
+ */
+void rtnl_link_vf_set_trust(struct rtnl_link_vf *vf_data, uint32_t vf_trust) {
+ vf_data->vf_trust = vf_trust;
+ vf_data->ce_mask |= SRIOV_ATTR_TRUST;
+
+ return;
+}
+
+/**
+ * Get an array of VLANS on SRIOV Virtual Function
+ * @arg vf_data SRIOV VF object
+ * @arg vf_vlans Pointer to nl_vf_vlans_t struct to store vlan info.
+ *
+ * @see rtnl_link_get_num_vf()
+ *
+ * The SRIOV VF VLANs object must be returned to the SRIOV VF object with
+ * rtnl_link_vf_vlans_put() when operations are done to prevent memory leaks.
+ *
+ * @copydoc pointer_lifetime_warning
+ * @return 0 if VLAN info is present and vf_vlans is set
+ * @return -NLE_OBJ_NOTFOUND if information for VF info is not found
+ * @return -NLE_NOATTR if the VF vlans is not set
+ */
+int rtnl_link_vf_get_vlans(struct rtnl_link_vf *vf_data,
+ nl_vf_vlans_t **vf_vlans) {
+ nl_vf_vlans_t *vf;
+
+ if (!vf_data)
+ return -NLE_OBJ_NOTFOUND;
+
+ if (vf_data->ce_mask & SRIOV_ATTR_VLAN) {
+ vf = vf_data->vf_vlans;
+ vf->ce_refcnt++;
+ *vf_vlans = vf;
+ } else
+ return -NLE_NOATTR;
+
+ return 0;
+}
+
+/**
+ * Add a SRIOV VF VLANs object to the SRIOV Virtual Function Object
+ * @param vf_data SRIOV VF object
+ * @param vf_vlans SRIOV VF VLANs object
+ *
+ * @see rtnl_link_vf_get_vlans()
+ * @see rtnl_link_vf_vlan_alloc()
+ *
+ * This function assigns ownership of the SRIOV VF object \p vf_vlans
+ * to the SRIOV Virtual Function object \p vf_data. Do not use
+ * rtnl_link_vf_vlan_put() on \p vf_vlans after this.
+ */
+void rtnl_link_vf_set_vlans(struct rtnl_link_vf *vf_data,
+ nl_vf_vlans_t *vf_vlans) {
+ if (!vf_data||!vf_vlans)
+ return;
+
+ vf_data->vf_vlans = vf_vlans;
+ vf_data->vf_vlans->ce_refcnt++;
+ vf_data->ce_mask |= SRIOV_ATTR_VLAN;
+
+ return;
+}
+
+/**
+ * Allocate a SRIOV VF VLAN object
+ * @param vf_vlans Pointer to store VLAN object at
+ * @param vlan_count Number of VLANs that will be stored in VLAN object
+ *
+ * The SRIOV VF VLANs object must be returned to the sRIOV VF object with
+ * rtnl_link_vf_vlan_put() when operations are done to prevent memory leaks.
+ *
+ * @return 0 if VLAN object is created and vf_vlans is set.
+ * @return -NLE_NOMEM if object could not be allocated.
+ * @return -NLE_INVAL if vlan_count is more than supported by SRIOV VF
+ */
+int rtnl_link_vf_vlan_alloc(nl_vf_vlans_t **vf_vlans, int vlan_count) {
+ nl_vf_vlans_t *vlans;
+ nl_vf_vlan_info_t *vlan_info;
+
+ if (vlan_count > MAX_VLAN_LIST_LEN)
+ return -NLE_INVAL;
+
+ vlans = calloc(1, sizeof(*vlans));
+ if (!vlans)
+ return -NLE_NOMEM;
+
+ vlan_info = calloc(vlan_count+1, sizeof(*vlan_info));
+ if (!vlan_info) {
+ free(vlans);
+ return -NLE_NOMEM;
+ }
+
+ NL_DBG(4, "Allocated new SRIOV VF VLANs object %p\n", vlans);
+
+ vlans->ce_refcnt = 1;
+ vlans->size = vlan_count;
+ vlans->vlans = vlan_info;
+ *vf_vlans = vlans;
+
+ return 0;
+}
+
+/**
+ * Free an allocated SRIOV VF VLANs object
+ * @param vf_vlans SRIOV VF VLANs object
+ */
+void rtnl_link_vf_vlan_free(nl_vf_vlans_t *vf_vlans) {
+ if (!vf_vlans)
+ return;
+
+ if (vf_vlans->ce_refcnt > 0)
+ NL_DBG(1, "Warning: Freeing SRIOV VF VLANs object in use...\n");
+
+ NL_DBG(4, "Freed SRIOV VF object %p\n", vf_vlans);
+ free(vf_vlans->vlans);
+ free(vf_vlans);
+
+ return;
+}
+
+/**
+ * Return SRIOV VF VLANs object to the owning SRIOV VF object.
+ * @param vf_vlans SRIOV VF VLANs object
+ */
+void rtnl_link_vf_vlan_put(nl_vf_vlans_t *vf_vlans) {
+ if (!vf_vlans)
+ return;
+
+ vf_vlans->ce_refcnt--;
+ NL_DBG(4, "Returned SRIOV VF VLANs object reference %p, %i remaining\n",
+ vf_vlans, vf_vlans->ce_refcnt);
+
+ if (vf_vlans->ce_refcnt < 0)
+ BUG();
+
+ if (vf_vlans->ce_refcnt <= 0)
+ rtnl_link_vf_vlan_free(vf_vlans);
+
+ return;
+}
+
+/** @} */
+
+/**
+ * @name Utilities
+ * @{
+ */
+
+static const struct trans_tbl vf_link_states[] = {
+ __ADD(IFLA_VF_LINK_STATE_AUTO, autodetect),
+ __ADD(IFLA_VF_LINK_STATE_ENABLE, up),
+ __ADD(IFLA_VF_LINK_STATE_DISABLE, down),
+};
+
+char *rtnl_link_vf_linkstate2str(uint32_t ls, char *buf, size_t len)
+{
+ return __type2str(ls, buf, len, vf_link_states,
+ ARRAY_SIZE(vf_link_states));
+}
+
+int rtnl_link_vf_str2linkstate(const char *name)
+{
+ return __str2type(name, vf_link_states, ARRAY_SIZE(vf_link_states));
+}
+
+static const struct trans_tbl vf_vlan_proto[] = {
+ __ADD(ETH_P_8021Q, 8021Q),
+ __ADD(ETH_P_8021AD, 8021AD),
+};
+
+char *rtnl_link_vf_vlanproto2str(uint16_t proto, char *buf, size_t len)
+{
+ return __type2str(proto, buf, len, vf_vlan_proto,
+ ARRAY_SIZE(vf_vlan_proto));
+}
+
+int rtnl_link_vf_str2vlanproto(const char *name)
+{
+ return __str2type(name, vf_vlan_proto, ARRAY_SIZE(vf_vlan_proto));
+}
+
+/* Return a guid from a format checked string.
+ * Format string must be xx:xx:xx:xx:xx:xx:xx:xx where XX can be an
+ * arbitrary hex digit
+ *
+ * Function modified from original at iproute2/lib/utils.c:get_guid()
+ * Original by Eli Cohen <eli@mellanox.com>.
+ * iproute2 git commit d91fb3f4c7e4dba806541bdc90b1fb60a3581541
+ */
+int rtnl_link_vf_str2guid(uint64_t *guid, const char *guid_s) {
+ unsigned long int tmp;
+ char *endptr;
+ int i;
+
+ if (strlen(guid_s) != RTNL_VF_GUID_STR_LEN)
+ return -1;
+
+ for (i = 0; i < 7; i++) {
+ if (guid_s[2 + i * 3] != ':')
+ return -1;
+ }
+
+ *guid = 0;
+ for (i = 0; i < 8; i++) {
+ tmp = strtoul(guid_s + i * 3, &endptr, 16);
+ if (endptr != guid_s + i * 3 + 2)
+ return -1;
+
+ if (tmp > 255)
+ return -1;
+
+ *guid |= tmp << (56 - 8 * i);
+ }
+
+ return 0;
+}
+
+/** @} */
+
+/** @} */
diff --git a/lib/route/link/veth.c b/lib/route/link/veth.c
index e7e4a268..15859de8 100644
--- a/lib/route/link/veth.c
+++ b/lib/route/link/veth.c
@@ -32,6 +32,7 @@
#include <netlink/route/link/veth.h>
#include <linux/if_link.h>
+#include <linux/veth.h>
static struct nla_policy veth_policy[VETH_INFO_MAX+1] = {
[VETH_INFO_PEER] = { .minlen = sizeof(struct ifinfomsg) },
@@ -45,7 +46,7 @@ static int veth_parse(struct rtnl_link *link, struct nlattr *data,
struct rtnl_link *peer = link->l_info;
int err;
- NL_DBG(3, "Parsing veth link info");
+ NL_DBG(3, "Parsing veth link info\n");
if ((err = nla_parse_nested(tb, VETH_INFO_MAX, data, veth_policy)) < 0)
goto errout;
@@ -62,8 +63,8 @@ static int veth_parse(struct rtnl_link *link, struct nlattr *data,
peer->l_index = ifi->ifi_index;
peer->l_flags = ifi->ifi_flags;
peer->l_change = ifi->ifi_change;
- err = nla_parse(peer_tb, IFLA_MAX,
- nla_data(nla_peer) + sizeof(struct ifinfomsg),
+ err = nla_parse(peer_tb, IFLA_MAX, (struct nlattr *)
+ ((char *) nla_data(nla_peer) + sizeof(struct ifinfomsg)),
nla_len(nla_peer) - sizeof(struct ifinfomsg),
rtln_link_policy);
if (err < 0)
@@ -281,10 +282,10 @@ int rtnl_link_veth_add(struct nl_sock *sock, const char *name,
return -NLE_NOMEM;
peer = link->l_info;
- if (name && peer_name) {
+ if (name)
rtnl_link_set_name(link, name);
+ if (peer_name)
rtnl_link_set_name(peer, peer_name);
- }
rtnl_link_set_ns_pid(peer, pid);
err = rtnl_link_add(sock, link, NLM_F_CREATE | NLM_F_EXCL);
diff --git a/lib/route/link/vlan.c b/lib/route/link/vlan.c
index b9f0c660..7c5aa069 100644
--- a/lib/route/link/vlan.c
+++ b/lib/route/link/vlan.c
@@ -44,6 +44,7 @@ struct vlan_info
{
uint16_t vi_vlan_id;
uint16_t vi_protocol;
+ unsigned int vi_ingress_qos_mask:(VLAN_PRIO_MAX+1);
uint32_t vi_flags;
uint32_t vi_flags_mask;
uint32_t vi_ingress_qos[VLAN_PRIO_MAX+1];
@@ -67,10 +68,16 @@ static int vlan_alloc(struct rtnl_link *link)
{
struct vlan_info *vi;
- if ((vi = calloc(1, sizeof(*vi))) == NULL)
- return -NLE_NOMEM;
+ if (link->l_info) {
+ vi = link->l_info;
+ free(vi->vi_egress_qos);
+ memset(link->l_info, 0, sizeof(*vi));
+ } else {
+ if ((vi = calloc(1, sizeof(*vi))) == NULL)
+ return -NLE_NOMEM;
- link->l_info = vi;
+ link->l_info = vi;
+ }
return 0;
}
@@ -82,7 +89,7 @@ static int vlan_parse(struct rtnl_link *link, struct nlattr *data,
struct vlan_info *vi;
int err;
- NL_DBG(3, "Parsing VLAN link info");
+ NL_DBG(3, "Parsing VLAN link info\n");
if ((err = nla_parse_nested(tb, IFLA_VLAN_MAX, data, vlan_policy)) < 0)
goto errout;
@@ -115,6 +122,7 @@ static int vlan_parse(struct rtnl_link *link, struct nlattr *data,
struct nlattr *nla;
int remaining;
+ vi->vi_ingress_qos_mask = 0;
memset(vi->vi_ingress_qos, 0, sizeof(vi->vi_ingress_qos));
nla_for_each_nested(nla, tb[IFLA_VLAN_INGRESS_QOS], remaining) {
@@ -126,6 +134,17 @@ static int vlan_parse(struct rtnl_link *link, struct nlattr *data,
return -NLE_INVAL;
}
+ /* Kernel will not explicitly serialize mappings with "to" zero
+ * (although they are implicitly set).
+ *
+ * Thus we only mark those as "set" which are explicitly sent.
+ * That is similar to what we do with the egress map and it preserves
+ * previous behavior before NL_CAPABILITY_RTNL_LINK_VLAN_INGRESS_MAP_CLEAR.
+ *
+ * It matters only when a received object is send back to kernel to modify
+ * the link.
+ */
+ vi->vi_ingress_qos_mask |= (1 << map->from);
vi->vi_ingress_qos[map->from] = map->to;
}
@@ -197,7 +216,7 @@ static void vlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump_line(p, " vlan-info id %d <%s>", vi->vi_vlan_id, buf);
if (vi->vi_mask & VLAN_HAS_PROTOCOL)
- nl_dump_line(p, " vlan protocol <%d>", vi->vi_protocol);
+ nl_dump_line(p, " vlan protocol <%d>", ntohs(vi->vi_protocol));
nl_dump(p, "\n");
@@ -205,7 +224,7 @@ static void vlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump_line(p,
" ingress vlan prio -> qos/socket prio mapping:\n");
for (i = 0, printed = 0; i <= VLAN_PRIO_MAX; i++) {
- if (vi->vi_ingress_qos[i]) {
+ if (vi->vi_ingress_qos_mask & (1 << i)) {
if (printed == 0)
nl_dump_line(p, " ");
nl_dump(p, "%x -> %#08x, ",
@@ -245,19 +264,28 @@ static int vlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
{
struct vlan_info *vdst, *vsrc = src->l_info;
int err;
+ struct vlan_map *p = NULL;
dst->l_info = NULL;
if ((err = rtnl_link_set_type(dst, "vlan")) < 0)
return err;
vdst = dst->l_info;
- vdst->vi_egress_qos = calloc(vsrc->vi_egress_size,
- sizeof(struct vlan_map));
- if (!vdst->vi_egress_qos)
- return -NLE_NOMEM;
+ if (vsrc->vi_negress) {
+ p = calloc(vsrc->vi_negress,
+ sizeof(struct vlan_map));
+ if (!p)
+ return -NLE_NOMEM;
+ }
+
+ *vdst = *vsrc;
- memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos,
- vsrc->vi_egress_size * sizeof(struct vlan_map));
+ if (vsrc->vi_negress) {
+ vdst->vi_egress_size = vsrc->vi_negress;
+ vdst->vi_egress_qos = p;
+ memcpy(vdst->vi_egress_qos, vsrc->vi_egress_qos,
+ vsrc->vi_negress * sizeof(struct vlan_map));
+ }
return 0;
}
@@ -273,6 +301,9 @@ static int vlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
if (vi->vi_mask & VLAN_HAS_ID)
NLA_PUT_U16(msg, IFLA_VLAN_ID, vi->vi_vlan_id);
+ if (vi->vi_mask & VLAN_HAS_PROTOCOL)
+ NLA_PUT_U16(msg, IFLA_VLAN_PROTOCOL, vi->vi_protocol);
+
if (vi->vi_mask & VLAN_HAS_FLAGS) {
struct ifla_vlan_flags flags = {
.flags = vi->vi_flags,
@@ -291,7 +322,7 @@ static int vlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
goto nla_put_failure;
for (i = 0; i <= VLAN_PRIO_MAX; i++) {
- if (vi->vi_ingress_qos[i]) {
+ if (vi->vi_ingress_qos_mask & (1 << i)) {
map.from = i;
map.to = vi->vi_ingress_qos[i];
@@ -425,7 +456,8 @@ int rtnl_link_vlan_get_id(struct rtnl_link *link)
/**
* Set VLAN protocol
* @arg link Link object
- * @arg protocol VLAN protocol
+ * @arg protocol VLAN protocol in network byte order.
+ * Probably you want to set it to something like htons(ETH_P_8021Q).
*
* @return 0 on success or a negative error code
*/
@@ -445,7 +477,8 @@ int rtnl_link_vlan_set_protocol(struct rtnl_link *link, uint16_t protocol)
* Get VLAN protocol
* @arg link Link object
*
- * @return VLAN protocol, 0 if not set or a negative error code.
+ * @return VLAN protocol in network byte order like htons(ETH_P_8021Q),
+ * 0 if not set or a negative error code.
*/
int rtnl_link_vlan_get_protocol(struct rtnl_link *link)
{
@@ -531,6 +564,7 @@ int rtnl_link_vlan_set_ingress_map(struct rtnl_link *link, int from,
if (from < 0 || from > VLAN_PRIO_MAX)
return -NLE_INVAL;
+ vi->vi_ingress_qos_mask |= (1 << from);
vi->vi_ingress_qos[from] = to;
vi->vi_mask |= VLAN_HAS_INGRESS_QOS;
@@ -561,10 +595,16 @@ int rtnl_link_vlan_set_egress_map(struct rtnl_link *link, uint32_t from, int to)
return -NLE_INVAL;
if (vi->vi_negress >= vi->vi_egress_size) {
- int new_size = vi->vi_egress_size + 32;
+ uint32_t new_size = vi->vi_egress_size + 1 + vi->vi_egress_size / 2;
+ size_t bytes;
void *ptr;
- ptr = realloc(vi->vi_egress_qos, new_size);
+ if (new_size < vi->vi_egress_size)
+ return -NLE_NOMEM;
+ bytes = (size_t) new_size * sizeof(struct vlan_map);
+ if (bytes / sizeof (struct vlan_map) != new_size)
+ return -NLE_NOMEM;
+ ptr = realloc(vi->vi_egress_qos, bytes);
if (!ptr)
return -NLE_NOMEM;
@@ -603,7 +643,10 @@ struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *link,
/** @} */
static const struct trans_tbl vlan_flags[] = {
- __ADD(VLAN_FLAG_REORDER_HDR, reorder_hdr)
+ __ADD(VLAN_FLAG_REORDER_HDR, reorder_hdr),
+ __ADD(VLAN_FLAG_GVRP, gvrp),
+ __ADD(VLAN_FLAG_LOOSE_BINDING, loose_binding),
+ __ADD(VLAN_FLAG_MVRP, mvrp),
};
/**
diff --git a/lib/route/link/vrf.c b/lib/route/link/vrf.c
new file mode 100644
index 00000000..8b6b451f
--- /dev/null
+++ b/lib/route/link/vrf.c
@@ -0,0 +1,264 @@
+/*
+ * lib/route/link/vrf.c VRF Link Info
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2015 Cumulus Networks. All rights reserved.
+ * Copyright (c) 2015 David Ahern <dsa@cumulusnetworks.com>
+ */
+
+/**
+ * @ingroup link
+ * @defgroup vrf VRF
+ * Virtual Routing and Forwarding link module
+ *
+ * @details
+ * \b Link Type Name: "vrf"
+ *
+ * @route_doc{link_vrf, VRF Documentation}
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink-private/route/link/api.h>
+#include <netlink/route/link/vrf.h>
+
+#include <linux/if_link.h>
+#include <linux-private/linux/rtnetlink.h>
+
+#define VRF_TABLE_ID_MAX RT_TABLE_MAX
+
+/** @cond SKIP */
+#define VRF_HAS_TABLE_ID (1<<0)
+
+struct vrf_info {
+ uint32_t table_id;
+ uint32_t vi_mask;
+};
+
+/** @endcond */
+
+static struct nla_policy vrf_policy[IFLA_VRF_MAX + 1] = {
+ [IFLA_VRF_TABLE] = { .type = NLA_U32 },
+};
+
+static int vrf_alloc(struct rtnl_link *link)
+{
+ struct vrf_info *vi;
+
+ if (link->l_info) {
+ memset(link->l_info, 0, sizeof (*vi));
+ return 0;
+ }
+
+ if ((vi = calloc(1, sizeof(*vi))) == NULL)
+ return -NLE_NOMEM;
+
+ link->l_info = vi;
+
+ return 0;
+}
+
+static int vrf_parse(struct rtnl_link *link, struct nlattr *data,
+ struct nlattr *xstats)
+{
+ struct nlattr *tb[IFLA_VRF_MAX+1];
+ struct vrf_info *vi;
+ int err;
+
+ NL_DBG(3, "Parsing VRF link info");
+
+ if ((err = nla_parse_nested(tb, IFLA_VRF_MAX, data, vrf_policy)) < 0)
+ goto errout;
+
+ if ((err = vrf_alloc(link)) < 0)
+ goto errout;
+
+ vi = link->l_info;
+
+ if (tb[IFLA_VRF_TABLE]) {
+ vi->table_id = nla_get_u32(tb[IFLA_VRF_TABLE]);
+ vi->vi_mask |= VRF_HAS_TABLE_ID;
+ }
+
+ err = 0;
+
+errout:
+ return err;
+}
+
+static void vrf_free(struct rtnl_link *link)
+{
+ free(link->l_info);
+ link->l_info = NULL;
+}
+
+static int vrf_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+ struct vrf_info *vdst, *vsrc = src->l_info;
+ int err;
+
+ dst->l_info = NULL;
+ if ((err = rtnl_link_set_type(dst, "vrf")) < 0)
+ return err;
+ vdst = dst->l_info;
+
+ BUG_ON(!vdst || !vsrc);
+
+ memcpy(vdst, vsrc, sizeof(struct vrf_info));
+
+ return 0;
+}
+
+static int vrf_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+ struct vrf_info *vi = link->l_info;
+ struct nlattr *data;
+
+ if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
+ return -NLE_NOMEM;
+
+ if (vi->vi_mask & VRF_HAS_TABLE_ID) {
+ NLA_PUT_U32(msg, IFLA_VRF_TABLE, vi->table_id);
+ }
+
+ nla_nest_end(msg, data);
+
+nla_put_failure:
+
+ return 0;
+}
+
+static void vrf_dump(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ struct vrf_info *vi = link->l_info;
+
+ if (vi->vi_mask & VRF_HAS_TABLE_ID) {
+ nl_dump(p, "table-id %u", vi->table_id);
+ }
+}
+
+static struct rtnl_link_info_ops vrf_info_ops = {
+ .io_name = "vrf",
+ .io_alloc = vrf_alloc,
+ .io_parse = vrf_parse,
+ .io_dump = {
+ [NL_DUMP_LINE] = vrf_dump,
+ [NL_DUMP_DETAILS] = vrf_dump,
+ },
+ .io_clone = vrf_clone,
+ .io_put_attrs = vrf_put_attrs,
+ .io_free = vrf_free,
+};
+
+/** @cond SKIP */
+#define IS_VRF_LINK_ASSERT(link) \
+ if ((link)->l_info_ops != &vrf_info_ops) { \
+ APPBUG("Link is not a VRF link. set type \"vrf\" first."); \
+ return -NLE_OPNOTSUPP; \
+ }
+/** @endcond */
+
+/**
+ * @name VRF Object
+ * @{
+ */
+
+/**
+ * Allocate link object of type VRF
+ *
+ * @return Allocated link object or NULL.
+ */
+struct rtnl_link *rtnl_link_vrf_alloc(void)
+{
+ struct rtnl_link *link;
+ int err;
+
+ if (!(link = rtnl_link_alloc()))
+ return NULL;
+
+ if ((err = rtnl_link_set_type(link, "vrf")) < 0) {
+ rtnl_link_put(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/**
+ * Check if link is a VRF link
+ * @arg link Link object
+ *
+ * @return True if link is a VRF link, otherwise false is returned.
+ */
+int rtnl_link_is_vrf(struct rtnl_link *link)
+{
+ return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "vrf");
+}
+
+/**
+ * Get VRF table id
+ * @arg link Link object
+ * @arg id Pointer to store table identifier
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vrf_get_tableid(struct rtnl_link *link, uint32_t *id)
+{
+ struct vrf_info *vi = link->l_info;
+
+ IS_VRF_LINK_ASSERT(link);
+ if(!id)
+ return -NLE_INVAL;
+
+ if (vi->vi_mask & VRF_HAS_TABLE_ID)
+ *id = vi->table_id;
+ else
+ return -NLE_AGAIN;
+
+ return 0;
+}
+
+/**
+ * Set VRF table id
+ * @arg link Link object
+ * @arg id Table identifier associated with VRF link
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vrf_set_tableid(struct rtnl_link *link, uint32_t id)
+{
+ struct vrf_info *vi = link->l_info;
+
+ IS_VRF_LINK_ASSERT(link);
+ if(id > VRF_TABLE_ID_MAX)
+ return -NLE_INVAL;
+
+ vi->table_id = id;
+ vi->vi_mask |= VRF_HAS_TABLE_ID;
+
+ return 0;
+}
+
+/** @} */
+
+static void __init vrf_init(void)
+{
+ rtnl_link_register_info(&vrf_info_ops);
+}
+
+static void __exit vrf_exit(void)
+{
+ rtnl_link_unregister_info(&vrf_info_ops);
+}
+
+/** @} */
diff --git a/lib/route/link/vxlan.c b/lib/route/link/vxlan.c
index f3e3538d..686ac31e 100644
--- a/lib/route/link/vxlan.c
+++ b/lib/route/link/vxlan.c
@@ -34,30 +34,44 @@
#include <linux/if_link.h>
/** @cond SKIP */
-#define VXLAN_HAS_ID (1<<0)
-#define VXLAN_HAS_GROUP (1<<1)
-#define VXLAN_HAS_LINK (1<<2)
-#define VXLAN_HAS_LOCAL (1<<3)
-#define VXLAN_HAS_TTL (1<<4)
-#define VXLAN_HAS_TOS (1<<5)
-#define VXLAN_HAS_LEARNING (1<<6)
-#define VXLAN_HAS_AGEING (1<<7)
-#define VXLAN_HAS_LIMIT (1<<8)
-#define VXLAN_HAS_PORT_RANGE (1<<9)
-#define VXLAN_HAS_PROXY (1<<10)
-#define VXLAN_HAS_RSC (1<<11)
-#define VXLAN_HAS_L2MISS (1<<12)
-#define VXLAN_HAS_L3MISS (1<<13)
+#define VXLAN_ATTR_ID (1<<0)
+#define VXLAN_ATTR_GROUP (1<<1)
+#define VXLAN_ATTR_LINK (1<<2)
+#define VXLAN_ATTR_LOCAL (1<<3)
+#define VXLAN_ATTR_TTL (1<<4)
+#define VXLAN_ATTR_TOS (1<<5)
+#define VXLAN_ATTR_LEARNING (1<<6)
+#define VXLAN_ATTR_AGEING (1<<7)
+#define VXLAN_ATTR_LIMIT (1<<8)
+#define VXLAN_ATTR_PORT_RANGE (1<<9)
+#define VXLAN_ATTR_PROXY (1<<10)
+#define VXLAN_ATTR_RSC (1<<11)
+#define VXLAN_ATTR_L2MISS (1<<12)
+#define VXLAN_ATTR_L3MISS (1<<13)
+#define VXLAN_ATTR_GROUP6 (1<<14)
+#define VXLAN_ATTR_LOCAL6 (1<<15)
+#define VXLAN_ATTR_PORT (1<<16)
+#define VXLAN_ATTR_UDP_CSUM (1<<17)
+#define VXLAN_ATTR_UDP_ZERO_CSUM6_TX (1<<18)
+#define VXLAN_ATTR_UDP_ZERO_CSUM6_RX (1<<19)
+#define VXLAN_ATTR_REMCSUM_TX (1<<20)
+#define VXLAN_ATTR_REMCSUM_RX (1<<21)
+#define VXLAN_ATTR_COLLECT_METADATA (1<<22)
+#define VXLAN_ATTR_LABEL (1<<23)
+#define VXLAN_ATTR_FLAGS (1<<24)
struct vxlan_info
{
uint32_t vxi_id;
uint32_t vxi_group;
+ struct in6_addr vxi_group6;
uint32_t vxi_link;
uint32_t vxi_local;
+ struct in6_addr vxi_local6;
uint8_t vxi_ttl;
uint8_t vxi_tos;
uint8_t vxi_learning;
+ uint8_t vxi_flags;
uint32_t vxi_ageing;
uint32_t vxi_limit;
struct ifla_vxlan_port_range vxi_port_range;
@@ -65,18 +79,29 @@ struct vxlan_info
uint8_t vxi_rsc;
uint8_t vxi_l2miss;
uint8_t vxi_l3miss;
- uint32_t vxi_mask;
+ uint16_t vxi_port;
+ uint8_t vxi_udp_csum;
+ uint8_t vxi_udp_zero_csum6_tx;
+ uint8_t vxi_udp_zero_csum6_rx;
+ uint8_t vxi_remcsum_tx;
+ uint8_t vxi_remcsum_rx;
+ uint8_t vxi_collect_metadata;
+ uint32_t vxi_label;
+ uint32_t ce_mask;
};
/** @endcond */
static struct nla_policy vxlan_policy[IFLA_VXLAN_MAX+1] = {
- [IFLA_VXLAN_ID] = { .type = NLA_U32 },
+ [IFLA_VXLAN_ID] = { .type = NLA_U32 },
[IFLA_VXLAN_GROUP] = { .minlen = sizeof(uint32_t) },
+ [IFLA_VXLAN_GROUP6] = { .minlen = sizeof(struct in6_addr) },
[IFLA_VXLAN_LINK] = { .type = NLA_U32 },
[IFLA_VXLAN_LOCAL] = { .minlen = sizeof(uint32_t) },
+ [IFLA_VXLAN_LOCAL6] = { .minlen = sizeof(struct in6_addr) },
[IFLA_VXLAN_TTL] = { .type = NLA_U8 },
[IFLA_VXLAN_TOS] = { .type = NLA_U8 },
+ [IFLA_VXLAN_LABEL] = { .type = NLA_U32 },
[IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
[IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
[IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
@@ -85,16 +110,30 @@ static struct nla_policy vxlan_policy[IFLA_VXLAN_MAX+1] = {
[IFLA_VXLAN_RSC] = { .type = NLA_U8 },
[IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
[IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
+ [IFLA_VXLAN_COLLECT_METADATA] = { .type = NLA_U8 },
+ [IFLA_VXLAN_PORT] = { .type = NLA_U16 },
+ [IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 },
+ [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
+ [IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
+ [IFLA_VXLAN_REMCSUM_TX] = { .type = NLA_U8 },
+ [IFLA_VXLAN_REMCSUM_RX] = { .type = NLA_U8 },
+ [IFLA_VXLAN_GBP] = { .type = NLA_FLAG, },
+ [IFLA_VXLAN_GPE] = { .type = NLA_FLAG, },
+ [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG },
};
static int vxlan_alloc(struct rtnl_link *link)
{
struct vxlan_info *vxi;
- if ((vxi = calloc(1, sizeof(*vxi))) == NULL)
- return -NLE_NOMEM;
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*vxi));
+ else {
+ if ((vxi = calloc(1, sizeof(*vxi))) == NULL)
+ return -NLE_NOMEM;
- link->l_info = vxi;
+ link->l_info = vxi;
+ }
return 0;
}
@@ -106,7 +145,7 @@ static int vxlan_parse(struct rtnl_link *link, struct nlattr *data,
struct vxlan_info *vxi;
int err;
- NL_DBG(3, "Parsing VXLAN link info");
+ NL_DBG(3, "Parsing VXLAN link info\n");
if ((err = nla_parse_nested(tb, IFLA_VXLAN_MAX, data, vxlan_policy)) < 0)
goto errout;
@@ -118,77 +157,140 @@ static int vxlan_parse(struct rtnl_link *link, struct nlattr *data,
if (tb[IFLA_VXLAN_ID]) {
vxi->vxi_id = nla_get_u32(tb[IFLA_VXLAN_ID]);
- vxi->vxi_mask |= VXLAN_HAS_ID;
+ vxi->ce_mask |= VXLAN_ATTR_ID;
+ }
+
+ if (tb[IFLA_VXLAN_GROUP6]) {
+ nla_memcpy(&vxi->vxi_group6, tb[IFLA_VXLAN_GROUP6],
+ sizeof(vxi->vxi_group6));
+ vxi->ce_mask |= VXLAN_ATTR_GROUP6;
}
if (tb[IFLA_VXLAN_GROUP]) {
nla_memcpy(&vxi->vxi_group, tb[IFLA_VXLAN_GROUP],
sizeof(vxi->vxi_group));
- vxi->vxi_mask |= VXLAN_HAS_GROUP;
+ vxi->ce_mask |= VXLAN_ATTR_GROUP;
+ vxi->ce_mask &= ~VXLAN_ATTR_GROUP6;
}
if (tb[IFLA_VXLAN_LINK]) {
vxi->vxi_link = nla_get_u32(tb[IFLA_VXLAN_LINK]);
- vxi->vxi_mask |= VXLAN_HAS_LINK;
+ vxi->ce_mask |= VXLAN_ATTR_LINK;
+ }
+
+ if (tb[IFLA_VXLAN_LOCAL6]) {
+ nla_memcpy(&vxi->vxi_local6, tb[IFLA_VXLAN_LOCAL6],
+ sizeof(vxi->vxi_local6));
+ vxi->ce_mask |= VXLAN_ATTR_LOCAL6;
}
if (tb[IFLA_VXLAN_LOCAL]) {
nla_memcpy(&vxi->vxi_local, tb[IFLA_VXLAN_LOCAL],
sizeof(vxi->vxi_local));
- vxi->vxi_mask |= VXLAN_HAS_LOCAL;
+ vxi->ce_mask |= VXLAN_ATTR_LOCAL;
+ vxi->ce_mask &= ~VXLAN_ATTR_LOCAL6;
}
if (tb[IFLA_VXLAN_TTL]) {
vxi->vxi_ttl = nla_get_u8(tb[IFLA_VXLAN_TTL]);
- vxi->vxi_mask |= VXLAN_HAS_TTL;
+ vxi->ce_mask |= VXLAN_ATTR_TTL;
}
if (tb[IFLA_VXLAN_TOS]) {
vxi->vxi_tos = nla_get_u8(tb[IFLA_VXLAN_TOS]);
- vxi->vxi_mask |= VXLAN_HAS_TOS;
+ vxi->ce_mask |= VXLAN_ATTR_TOS;
}
if (tb[IFLA_VXLAN_LEARNING]) {
vxi->vxi_learning = nla_get_u8(tb[IFLA_VXLAN_LEARNING]);
- vxi->vxi_mask |= VXLAN_HAS_LEARNING;
+ vxi->ce_mask |= VXLAN_ATTR_LEARNING;
}
if (tb[IFLA_VXLAN_AGEING]) {
vxi->vxi_ageing = nla_get_u32(tb[IFLA_VXLAN_AGEING]);
- vxi->vxi_mask |= VXLAN_HAS_AGEING;
+ vxi->ce_mask |= VXLAN_ATTR_AGEING;
}
if (tb[IFLA_VXLAN_LIMIT]) {
vxi->vxi_limit = nla_get_u32(tb[IFLA_VXLAN_LIMIT]);
- vxi->vxi_mask |= VXLAN_HAS_LIMIT;
+ vxi->ce_mask |= VXLAN_ATTR_LIMIT;
}
if (tb[IFLA_VXLAN_PORT_RANGE]) {
nla_memcpy(&vxi->vxi_port_range, tb[IFLA_VXLAN_PORT_RANGE],
sizeof(vxi->vxi_port_range));
- vxi->vxi_mask |= VXLAN_HAS_PORT_RANGE;
+ vxi->ce_mask |= VXLAN_ATTR_PORT_RANGE;
}
if (tb[IFLA_VXLAN_PROXY]) {
vxi->vxi_proxy = nla_get_u8(tb[IFLA_VXLAN_PROXY]);
- vxi->vxi_mask |= VXLAN_HAS_PROXY;
+ vxi->ce_mask |= VXLAN_ATTR_PROXY;
}
if (tb[IFLA_VXLAN_RSC]) {
vxi->vxi_rsc = nla_get_u8(tb[IFLA_VXLAN_RSC]);
- vxi->vxi_mask |= VXLAN_HAS_RSC;
+ vxi->ce_mask |= VXLAN_ATTR_RSC;
}
if (tb[IFLA_VXLAN_L2MISS]) {
vxi->vxi_l2miss = nla_get_u8(tb[IFLA_VXLAN_L2MISS]);
- vxi->vxi_mask |= VXLAN_HAS_L2MISS;
+ vxi->ce_mask |= VXLAN_ATTR_L2MISS;
}
if (tb[IFLA_VXLAN_L3MISS]) {
vxi->vxi_l3miss = nla_get_u8(tb[IFLA_VXLAN_L3MISS]);
- vxi->vxi_mask |= VXLAN_HAS_L3MISS;
+ vxi->ce_mask |= VXLAN_ATTR_L3MISS;
+ }
+
+ if (tb[IFLA_VXLAN_PORT]) {
+ vxi->vxi_port = nla_get_u16(tb[IFLA_VXLAN_PORT]);
+ vxi->ce_mask |= VXLAN_ATTR_PORT;
+ }
+
+ if (tb[IFLA_VXLAN_UDP_CSUM]) {
+ vxi->vxi_udp_csum = nla_get_u8(tb[IFLA_VXLAN_UDP_CSUM]);
+ vxi->ce_mask |= VXLAN_ATTR_UDP_CSUM;
+ }
+
+ if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]) {
+ vxi->vxi_udp_zero_csum6_tx = nla_get_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_TX]);
+ vxi->ce_mask |= VXLAN_ATTR_UDP_ZERO_CSUM6_TX;
+ }
+
+ if (tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]) {
+ vxi->vxi_udp_zero_csum6_rx = nla_get_u8(tb[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]);
+ vxi->ce_mask |= VXLAN_ATTR_UDP_ZERO_CSUM6_RX;
+ }
+
+ if (tb[IFLA_VXLAN_REMCSUM_TX]) {
+ vxi->vxi_remcsum_tx = nla_get_u8(tb[IFLA_VXLAN_REMCSUM_TX]);
+ vxi->ce_mask |= VXLAN_ATTR_REMCSUM_TX;
+ }
+
+ if (tb[IFLA_VXLAN_REMCSUM_RX]) {
+ vxi->vxi_remcsum_rx = nla_get_u8(tb[IFLA_VXLAN_REMCSUM_RX]);
+ vxi->ce_mask |= VXLAN_ATTR_REMCSUM_RX;
+ }
+
+ if (tb[IFLA_VXLAN_GBP])
+ vxi->vxi_flags |= RTNL_LINK_VXLAN_F_GBP;
+
+ if (tb[IFLA_VXLAN_REMCSUM_NOPARTIAL])
+ vxi->vxi_flags |= RTNL_LINK_VXLAN_F_REMCSUM_NOPARTIAL;
+
+ if (tb[IFLA_VXLAN_COLLECT_METADATA]) {
+ vxi->vxi_collect_metadata = nla_get_u8(tb[IFLA_VXLAN_COLLECT_METADATA]);
+ vxi->ce_mask |= VXLAN_ATTR_COLLECT_METADATA;
}
+ if (tb[IFLA_VXLAN_LABEL]) {
+ vxi->vxi_label = nla_get_u32(tb[IFLA_VXLAN_LABEL]);
+ vxi->ce_mask |= VXLAN_ATTR_LABEL;
+ }
+
+ if (tb[IFLA_VXLAN_GPE])
+ vxi->vxi_flags |= RTNL_LINK_VXLAN_F_GPE;
+
err = 0;
errout:
@@ -213,36 +315,55 @@ static void vxlan_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
{
struct vxlan_info *vxi = link->l_info;
- char *name, addr[INET_ADDRSTRLEN];
+ char *name, addr[INET6_ADDRSTRLEN];
+ struct rtnl_link *parent;
nl_dump_line(p, " vxlan-id %u\n", vxi->vxi_id);
- if (vxi->vxi_mask & VXLAN_HAS_GROUP) {
+ if (vxi->ce_mask & VXLAN_ATTR_GROUP) {
nl_dump(p, " group ");
- if(inet_ntop(AF_INET, &vxi->vxi_group, addr, sizeof(addr)))
+ if (inet_ntop(AF_INET, &vxi->vxi_group, addr, sizeof(addr)))
nl_dump_line(p, "%s\n", addr);
else
nl_dump_line(p, "%#x\n", ntohs(vxi->vxi_group));
+ } else if (vxi->ce_mask & VXLAN_ATTR_GROUP6) {
+ nl_dump(p, " group ");
+ if (inet_ntop(AF_INET6, &vxi->vxi_group6, addr, sizeof(addr)))
+ nl_dump_line(p, "%s\n", addr);
+ else
+ nl_dump_line(p, "%#x\n", vxi->vxi_group6);
}
- if (vxi->vxi_mask & VXLAN_HAS_LINK) {
+ if (vxi->ce_mask & VXLAN_ATTR_LINK) {
nl_dump(p, " link ");
- name = rtnl_link_get_name(link);
+
+ name = NULL;
+ parent = link_lookup(link->ce_cache, vxi->vxi_link);
+ if (parent)
+ name = rtnl_link_get_name(parent);
+
if (name)
nl_dump_line(p, "%s\n", name);
else
nl_dump_line(p, "%u\n", vxi->vxi_link);
}
- if (vxi->vxi_mask & VXLAN_HAS_LOCAL) {
+ if (vxi->ce_mask & VXLAN_ATTR_LOCAL) {
nl_dump(p, " local ");
- if(inet_ntop(AF_INET, &vxi->vxi_local, addr, sizeof(addr)))
+ if (inet_ntop(AF_INET, &vxi->vxi_local, addr, sizeof(addr)))
nl_dump_line(p, "%s\n", addr);
else
nl_dump_line(p, "%#x\n", ntohs(vxi->vxi_local));
+ } else if (vxi->ce_mask & VXLAN_ATTR_LOCAL6) {
+ nl_dump(p, " local ");
+ if (inet_ntop(AF_INET6, &vxi->vxi_local6, addr, sizeof(addr)))
+ nl_dump_line(p, "%s\n", addr);
+ else
+ nl_dump_line(p, "%#x\n", vxi->vxi_local6);
}
- if (vxi->vxi_mask & VXLAN_HAS_TTL) {
+
+ if (vxi->ce_mask & VXLAN_ATTR_TTL) {
nl_dump(p, " ttl ");
if(vxi->vxi_ttl)
nl_dump_line(p, "%u\n", vxi->vxi_ttl);
@@ -250,7 +371,7 @@ static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump_line(p, "inherit\n");
}
- if (vxi->vxi_mask & VXLAN_HAS_TOS) {
+ if (vxi->ce_mask & VXLAN_ATTR_TOS) {
nl_dump(p, " tos ");
if (vxi->vxi_tos == 1)
nl_dump_line(p, "inherit\n", vxi->vxi_tos);
@@ -258,7 +379,7 @@ static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump_line(p, "%#x\n", vxi->vxi_tos);
}
- if (vxi->vxi_mask & VXLAN_HAS_LEARNING) {
+ if (vxi->ce_mask & VXLAN_ATTR_LEARNING) {
nl_dump(p, " learning ");
if (vxi->vxi_learning)
nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_learning);
@@ -266,7 +387,7 @@ static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump_line(p, "disabled\n");
}
- if (vxi->vxi_mask & VXLAN_HAS_AGEING) {
+ if (vxi->ce_mask & VXLAN_ATTR_AGEING) {
nl_dump(p, " ageing ");
if (vxi->vxi_ageing)
nl_dump_line(p, "%u seconds\n", vxi->vxi_ageing);
@@ -274,7 +395,7 @@ static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump_line(p, "disabled\n");
}
- if (vxi->vxi_mask & VXLAN_HAS_LIMIT) {
+ if (vxi->ce_mask & VXLAN_ATTR_LIMIT) {
nl_dump(p, " limit ");
if (vxi->vxi_limit)
nl_dump_line(p, "%u\n", vxi->vxi_limit);
@@ -282,12 +403,12 @@ static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump_line(p, "unlimited\n");
}
- if (vxi->vxi_mask & VXLAN_HAS_PORT_RANGE)
+ if (vxi->ce_mask & VXLAN_ATTR_PORT_RANGE)
nl_dump_line(p, " port range %u - %u\n",
ntohs(vxi->vxi_port_range.low),
ntohs(vxi->vxi_port_range.high));
- if (vxi->vxi_mask & VXLAN_HAS_PROXY) {
+ if (vxi->ce_mask & VXLAN_ATTR_PROXY) {
nl_dump(p, " proxy ");
if (vxi->vxi_proxy)
nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_proxy);
@@ -295,7 +416,7 @@ static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump_line(p, "disabled\n");
}
- if (vxi->vxi_mask & VXLAN_HAS_RSC) {
+ if (vxi->ce_mask & VXLAN_ATTR_RSC) {
nl_dump(p, " rsc ");
if (vxi->vxi_rsc)
nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_rsc);
@@ -303,7 +424,7 @@ static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump_line(p, "disabled\n");
}
- if (vxi->vxi_mask & VXLAN_HAS_L2MISS) {
+ if (vxi->ce_mask & VXLAN_ATTR_L2MISS) {
nl_dump(p, " l2miss ");
if (vxi->vxi_l2miss)
nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_l2miss);
@@ -311,13 +432,80 @@ static void vxlan_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
nl_dump_line(p, "disabled\n");
}
- if (vxi->vxi_mask & VXLAN_HAS_L3MISS) {
+ if (vxi->ce_mask & VXLAN_ATTR_L3MISS) {
nl_dump(p, " l3miss ");
if (vxi->vxi_l3miss)
nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_l3miss);
else
nl_dump_line(p, "disabled\n");
}
+
+ if (vxi->ce_mask & VXLAN_ATTR_PORT) {
+ nl_dump(p, " port ");
+ nl_dump_line(p, "%u\n", ntohs(vxi->vxi_port));
+ }
+
+ if (vxi->ce_mask & VXLAN_ATTR_UDP_CSUM) {
+ nl_dump(p, " UDP checksums ");
+ if (vxi->vxi_udp_csum)
+ nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_udp_csum);
+ else
+ nl_dump_line(p, "disabled\n");
+ }
+
+ if (vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_TX) {
+ nl_dump(p, " udp-zero-csum6-tx ");
+ if (vxi->vxi_udp_zero_csum6_tx)
+ nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_udp_zero_csum6_tx);
+ else
+ nl_dump_line(p, "disabled\n");
+ }
+
+ if (vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_RX) {
+ nl_dump(p, " udp-zero-csum6-rx ");
+ if (vxi->vxi_udp_zero_csum6_rx)
+ nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_udp_zero_csum6_rx);
+ else
+ nl_dump_line(p, "disabled\n");
+ }
+
+ if (vxi->ce_mask & VXLAN_ATTR_REMCSUM_TX) {
+ nl_dump(p, " remcsum-tx ");
+ if (vxi->vxi_remcsum_tx)
+ nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_remcsum_tx);
+ else
+ nl_dump_line(p, "disabled\n");
+ }
+
+ if (vxi->ce_mask & VXLAN_ATTR_REMCSUM_RX) {
+ nl_dump(p, " remcsum-rx ");
+ if (vxi->vxi_remcsum_rx)
+ nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_remcsum_rx);
+ else
+ nl_dump_line(p, "disabled\n");
+ }
+
+ if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_GBP)
+ nl_dump(p, " gbp\n");
+
+ if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_REMCSUM_NOPARTIAL)
+ nl_dump(p, " rncsum-nopartial\n");
+
+ if (vxi->ce_mask & VXLAN_ATTR_COLLECT_METADATA) {
+ nl_dump(p, " remcsum-rx ");
+ if (vxi->vxi_collect_metadata)
+ nl_dump_line(p, "enabled (%#x)\n", vxi->vxi_collect_metadata);
+ else
+ nl_dump_line(p, "disabled\n");
+ }
+
+ if (vxi->ce_mask & VXLAN_ATTR_LABEL) {
+ nl_dump(p, " label ");
+ nl_dump_line(p, "%u\n", ntohl(vxi->vxi_label));
+ }
+
+ if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_GPE)
+ nl_dump(p, " gpe\n");
}
static int vxlan_clone(struct rtnl_link *dst, struct rtnl_link *src)
@@ -346,49 +534,88 @@ static int vxlan_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
if (!(data = nla_nest_start(msg, IFLA_INFO_DATA)))
return -NLE_MSGSIZE;
- if (vxi->vxi_mask & VXLAN_HAS_ID)
+ if (vxi->ce_mask & VXLAN_ATTR_ID)
NLA_PUT_U32(msg, IFLA_VXLAN_ID, vxi->vxi_id);
- if (vxi->vxi_mask & VXLAN_HAS_GROUP)
+ if (vxi->ce_mask & VXLAN_ATTR_GROUP)
NLA_PUT(msg, IFLA_VXLAN_GROUP, sizeof(vxi->vxi_group), &vxi->vxi_group);
- if (vxi->vxi_mask & VXLAN_HAS_LINK)
+ if (vxi->ce_mask & VXLAN_ATTR_GROUP6)
+ NLA_PUT(msg, IFLA_VXLAN_GROUP6, sizeof(vxi->vxi_group6), &vxi->vxi_group6);
+
+ if (vxi->ce_mask & VXLAN_ATTR_LINK)
NLA_PUT_U32(msg, IFLA_VXLAN_LINK, vxi->vxi_link);
- if (vxi->vxi_mask & VXLAN_HAS_LOCAL)
+ if (vxi->ce_mask & VXLAN_ATTR_LOCAL)
NLA_PUT(msg, IFLA_VXLAN_LOCAL, sizeof(vxi->vxi_local), &vxi->vxi_local);
- if (vxi->vxi_mask & VXLAN_HAS_TTL)
+ if (vxi->ce_mask & VXLAN_ATTR_LOCAL6)
+ NLA_PUT(msg, IFLA_VXLAN_LOCAL6, sizeof(vxi->vxi_local6), &vxi->vxi_local6);
+
+ if (vxi->ce_mask & VXLAN_ATTR_TTL)
NLA_PUT_U8(msg, IFLA_VXLAN_TTL, vxi->vxi_ttl);
- if (vxi->vxi_mask & VXLAN_HAS_TOS)
+ if (vxi->ce_mask & VXLAN_ATTR_TOS)
NLA_PUT_U8(msg, IFLA_VXLAN_TOS, vxi->vxi_tos);
- if (vxi->vxi_mask & VXLAN_HAS_LEARNING)
+ if (vxi->ce_mask & VXLAN_ATTR_LEARNING)
NLA_PUT_U8(msg, IFLA_VXLAN_LEARNING, vxi->vxi_learning);
- if (vxi->vxi_mask & VXLAN_HAS_AGEING)
+ if (vxi->ce_mask & VXLAN_ATTR_AGEING)
NLA_PUT_U32(msg, IFLA_VXLAN_AGEING, vxi->vxi_ageing);
- if (vxi->vxi_mask & VXLAN_HAS_LIMIT)
+ if (vxi->ce_mask & VXLAN_ATTR_LIMIT)
NLA_PUT_U32(msg, IFLA_VXLAN_LIMIT, vxi->vxi_limit);
- if (vxi->vxi_mask & VXLAN_HAS_PORT_RANGE)
+ if (vxi->ce_mask & VXLAN_ATTR_PORT_RANGE)
NLA_PUT(msg, IFLA_VXLAN_PORT_RANGE, sizeof(vxi->vxi_port_range),
&vxi->vxi_port_range);
- if (vxi->vxi_mask & VXLAN_HAS_PROXY)
+ if (vxi->ce_mask & VXLAN_ATTR_PROXY)
NLA_PUT_U8(msg, IFLA_VXLAN_PROXY, vxi->vxi_proxy);
- if (vxi->vxi_mask & VXLAN_HAS_RSC)
+ if (vxi->ce_mask & VXLAN_ATTR_RSC)
NLA_PUT_U8(msg, IFLA_VXLAN_RSC, vxi->vxi_rsc);
- if (vxi->vxi_mask & VXLAN_HAS_L2MISS)
+ if (vxi->ce_mask & VXLAN_ATTR_L2MISS)
NLA_PUT_U8(msg, IFLA_VXLAN_L2MISS, vxi->vxi_l2miss);
- if (vxi->vxi_mask & VXLAN_HAS_L3MISS)
+ if (vxi->ce_mask & VXLAN_ATTR_L3MISS)
NLA_PUT_U8(msg, IFLA_VXLAN_L3MISS, vxi->vxi_l3miss);
+ if (vxi->ce_mask & VXLAN_ATTR_PORT)
+ NLA_PUT_U32(msg, IFLA_VXLAN_PORT, vxi->vxi_port);
+
+ if (vxi->ce_mask & VXLAN_ATTR_UDP_CSUM)
+ NLA_PUT_U8(msg, IFLA_VXLAN_UDP_CSUM, vxi->vxi_udp_csum);
+
+ if (vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_TX)
+ NLA_PUT_U8(msg, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, vxi->vxi_udp_zero_csum6_tx);
+
+ if (vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_RX)
+ NLA_PUT_U8(msg, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, vxi->vxi_udp_zero_csum6_rx);
+
+ if (vxi->ce_mask & VXLAN_ATTR_REMCSUM_TX)
+ NLA_PUT_U8(msg, IFLA_VXLAN_REMCSUM_TX, vxi->vxi_remcsum_tx);
+
+ if (vxi->ce_mask & VXLAN_ATTR_REMCSUM_RX)
+ NLA_PUT_U8(msg, IFLA_VXLAN_REMCSUM_RX, vxi->vxi_remcsum_rx);
+
+ if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_GBP)
+ NLA_PUT_FLAG(msg, IFLA_VXLAN_GBP);
+
+ if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_REMCSUM_NOPARTIAL)
+ NLA_PUT_FLAG(msg, IFLA_VXLAN_REMCSUM_NOPARTIAL);
+
+ if (vxi->ce_mask & VXLAN_ATTR_COLLECT_METADATA)
+ NLA_PUT_U8(msg, IFLA_VXLAN_COLLECT_METADATA, vxi->vxi_collect_metadata);
+
+ if (vxi->ce_mask & VXLAN_ATTR_LABEL)
+ NLA_PUT_U32(msg, IFLA_VXLAN_LABEL, vxi->vxi_label);
+
+ if (vxi->vxi_flags & RTNL_LINK_VXLAN_F_GPE)
+ NLA_PUT_FLAG(msg, IFLA_VXLAN_GPE);
+
nla_nest_end(msg, data);
nla_put_failure:
@@ -396,6 +623,49 @@ nla_put_failure:
return 0;
}
+static int vxlan_compare(struct rtnl_link *link_a, struct rtnl_link *link_b,
+ int flags)
+{
+ struct vxlan_info *a = link_a->l_info;
+ struct vxlan_info *b = link_b->l_info;
+ int diff = 0;
+ uint32_t attrs = flags & LOOSE_COMPARISON ? b->ce_mask : ~0;
+
+#define VXLAN_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, VXLAN_ATTR_##ATTR, a, b, EXPR)
+
+ diff |= VXLAN_DIFF(ID, a->vxi_id != b->vxi_id);
+ diff |= VXLAN_DIFF(GROUP, a->vxi_group != b->vxi_group);
+ diff |= VXLAN_DIFF(LINK, a->vxi_link != b->vxi_link);
+ diff |= VXLAN_DIFF(LOCAL, a->vxi_local != b->vxi_local);
+ diff |= VXLAN_DIFF(TOS, a->vxi_tos != b->vxi_tos);
+ diff |= VXLAN_DIFF(TTL, a->vxi_ttl != b->vxi_ttl);
+ diff |= VXLAN_DIFF(LEARNING, a->vxi_learning != b->vxi_learning);
+ diff |= VXLAN_DIFF(AGEING, a->vxi_ageing != b->vxi_ageing);
+ diff |= VXLAN_DIFF(LIMIT, a->vxi_limit != b->vxi_limit);
+ diff |= VXLAN_DIFF(PORT_RANGE,
+ a->vxi_port_range.low != b->vxi_port_range.low);
+ diff |= VXLAN_DIFF(PORT_RANGE,
+ a->vxi_port_range.high != b->vxi_port_range.high);
+ diff |= VXLAN_DIFF(PROXY, a->vxi_proxy != b->vxi_proxy);
+ diff |= VXLAN_DIFF(RSC, a->vxi_proxy != b->vxi_proxy);
+ diff |= VXLAN_DIFF(L2MISS, a->vxi_proxy != b->vxi_proxy);
+ diff |= VXLAN_DIFF(L3MISS, a->vxi_proxy != b->vxi_proxy);
+ diff |= VXLAN_DIFF(PORT, a->vxi_port != b->vxi_port);
+ diff |= VXLAN_DIFF(GROUP6, memcmp(&a->vxi_group6, &b->vxi_group6, sizeof(a->vxi_group6)) != 0);
+ diff |= VXLAN_DIFF(LOCAL6, memcmp(&a->vxi_local6, &b->vxi_local6, sizeof(a->vxi_local6)) != 0);
+ diff |= VXLAN_DIFF(UDP_CSUM, a->vxi_proxy != b->vxi_proxy);
+ diff |= VXLAN_DIFF(UDP_ZERO_CSUM6_TX, a->vxi_proxy != b->vxi_proxy);
+ diff |= VXLAN_DIFF(UDP_ZERO_CSUM6_RX, a->vxi_proxy != b->vxi_proxy);
+ diff |= VXLAN_DIFF(REMCSUM_TX, a->vxi_proxy != b->vxi_proxy);
+ diff |= VXLAN_DIFF(REMCSUM_RX, a->vxi_proxy != b->vxi_proxy);
+ diff |= VXLAN_DIFF(COLLECT_METADATA, a->vxi_collect_metadata != b->vxi_collect_metadata);
+ diff |= VXLAN_DIFF(LABEL, a->vxi_label != b->vxi_label);
+ diff |= VXLAN_DIFF(FLAGS, a->vxi_flags != b->vxi_flags);
+#undef VXLAN_DIFF
+
+ return diff;
+}
+
static struct rtnl_link_info_ops vxlan_info_ops = {
.io_name = "vxlan",
.io_alloc = vxlan_alloc,
@@ -407,6 +677,7 @@ static struct rtnl_link_info_ops vxlan_info_ops = {
.io_clone = vxlan_clone,
.io_put_attrs = vxlan_put_attrs,
.io_free = vxlan_free,
+ .io_compare = vxlan_compare,
};
/** @cond SKIP */
@@ -471,7 +742,7 @@ int rtnl_link_vxlan_set_id(struct rtnl_link *link, uint32_t id)
return -NLE_INVAL;
vxi->vxi_id = id;
- vxi->vxi_mask |= VXLAN_HAS_ID;
+ vxi->ce_mask |= VXLAN_ATTR_ID;
return 0;
}
@@ -492,7 +763,7 @@ int rtnl_link_vxlan_get_id(struct rtnl_link *link, uint32_t *id)
if(!id)
return -NLE_INVAL;
- if (vxi->vxi_mask & VXLAN_HAS_ID)
+ if (vxi->ce_mask & VXLAN_ATTR_ID)
*id = vxi->vxi_id;
else
return -NLE_AGAIN;
@@ -513,14 +784,21 @@ int rtnl_link_vxlan_set_group(struct rtnl_link *link, struct nl_addr *addr)
IS_VXLAN_LINK_ASSERT(link);
- if ((nl_addr_get_family(addr) != AF_INET) ||
- (nl_addr_get_len(addr) != sizeof(vxi->vxi_group)))
+ if ((nl_addr_get_family(addr) == AF_INET) &&
+ (nl_addr_get_len(addr) == sizeof(vxi->vxi_group))) {
+ memcpy(&vxi->vxi_group, nl_addr_get_binary_addr(addr),
+ sizeof(vxi->vxi_group));
+ vxi->ce_mask |= VXLAN_ATTR_GROUP;
+ vxi->ce_mask &= ~VXLAN_ATTR_GROUP6;
+ } else if ((nl_addr_get_family(addr) == AF_INET6) &&
+ (nl_addr_get_len(addr) == sizeof(vxi->vxi_group6))) {
+ memcpy(&vxi->vxi_group6, nl_addr_get_binary_addr(addr),
+ sizeof(vxi->vxi_group6));
+ vxi->ce_mask |= VXLAN_ATTR_GROUP6;
+ vxi->ce_mask &= ~VXLAN_ATTR_GROUP;
+ } else
return -NLE_INVAL;
- memcpy(&vxi->vxi_group, nl_addr_get_binary_addr(addr),
- sizeof(vxi->vxi_group));
- vxi->vxi_mask |= VXLAN_HAS_GROUP;
-
return 0;
}
@@ -540,11 +818,13 @@ int rtnl_link_vxlan_get_group(struct rtnl_link *link, struct nl_addr **addr)
if (!addr)
return -NLE_INVAL;
- if (!(vxi->vxi_mask & VXLAN_HAS_GROUP))
+ if (vxi->ce_mask & VXLAN_ATTR_GROUP)
+ *addr = nl_addr_build(AF_INET, &vxi->vxi_group, sizeof(vxi->vxi_group));
+ else if (vxi->ce_mask & VXLAN_ATTR_GROUP6)
+ *addr = nl_addr_build(AF_INET6, &vxi->vxi_group6, sizeof(vxi->vxi_group6));
+ else
return -NLE_AGAIN;
- *addr = nl_addr_build(AF_INET, &vxi->vxi_group, sizeof(vxi->vxi_group));
-
return 0;
}
@@ -562,7 +842,7 @@ int rtnl_link_vxlan_set_link(struct rtnl_link *link, uint32_t index)
IS_VXLAN_LINK_ASSERT(link);
vxi->vxi_link = index;
- vxi->vxi_mask |= VXLAN_HAS_LINK;
+ vxi->ce_mask |= VXLAN_ATTR_LINK;
return 0;
}
@@ -583,7 +863,7 @@ int rtnl_link_vxlan_get_link(struct rtnl_link *link, uint32_t *index)
if (!index)
return -NLE_INVAL;
- if (!(vxi->vxi_mask & VXLAN_HAS_LINK))
+ if (!(vxi->ce_mask & VXLAN_ATTR_LINK))
return -NLE_AGAIN;
*index = vxi->vxi_link;
@@ -604,14 +884,21 @@ int rtnl_link_vxlan_set_local(struct rtnl_link *link, struct nl_addr *addr)
IS_VXLAN_LINK_ASSERT(link);
- if ((nl_addr_get_family(addr) != AF_INET) ||
- (nl_addr_get_len(addr) != sizeof(vxi->vxi_local)))
+ if ((nl_addr_get_family(addr) == AF_INET) &&
+ (nl_addr_get_len(addr) == sizeof(vxi->vxi_local))) {
+ memcpy(&vxi->vxi_local, nl_addr_get_binary_addr(addr),
+ sizeof(vxi->vxi_local));
+ vxi->ce_mask |= VXLAN_ATTR_LOCAL;
+ vxi->ce_mask &= ~VXLAN_ATTR_LOCAL6;
+ } else if ((nl_addr_get_family(addr) == AF_INET6) &&
+ (nl_addr_get_len(addr) == sizeof(vxi->vxi_local6))) {
+ memcpy(&vxi->vxi_local6, nl_addr_get_binary_addr(addr),
+ sizeof(vxi->vxi_local6));
+ vxi->ce_mask |= VXLAN_ATTR_LOCAL6;
+ vxi->ce_mask &= ~VXLAN_ATTR_LOCAL;
+ } else
return -NLE_INVAL;
- memcpy(&vxi->vxi_local, nl_addr_get_binary_addr(addr),
- sizeof(vxi->vxi_local));
- vxi->vxi_mask |= VXLAN_HAS_LOCAL;
-
return 0;
}
@@ -631,11 +918,13 @@ int rtnl_link_vxlan_get_local(struct rtnl_link *link, struct nl_addr **addr)
if (!addr)
return -NLE_INVAL;
- if (!(vxi->vxi_mask & VXLAN_HAS_LOCAL))
+ if (vxi->ce_mask & VXLAN_ATTR_LOCAL)
+ *addr = nl_addr_build(AF_INET, &vxi->vxi_local, sizeof(vxi->vxi_local));
+ else if (vxi->ce_mask & VXLAN_ATTR_LOCAL6)
+ *addr = nl_addr_build(AF_INET6, &vxi->vxi_local6, sizeof(vxi->vxi_local6));
+ else
return -NLE_AGAIN;
- *addr = nl_addr_build(AF_INET, &vxi->vxi_local, sizeof(vxi->vxi_local));
-
return 0;
}
@@ -653,7 +942,7 @@ int rtnl_link_vxlan_set_ttl(struct rtnl_link *link, uint8_t ttl)
IS_VXLAN_LINK_ASSERT(link);
vxi->vxi_ttl = ttl;
- vxi->vxi_mask |= VXLAN_HAS_TTL;
+ vxi->ce_mask |= VXLAN_ATTR_TTL;
return 0;
}
@@ -670,7 +959,7 @@ int rtnl_link_vxlan_get_ttl(struct rtnl_link *link)
IS_VXLAN_LINK_ASSERT(link);
- if (!(vxi->vxi_mask & VXLAN_HAS_TTL))
+ if (!(vxi->ce_mask & VXLAN_ATTR_TTL))
return -NLE_AGAIN;
return vxi->vxi_ttl;
@@ -690,7 +979,7 @@ int rtnl_link_vxlan_set_tos(struct rtnl_link *link, uint8_t tos)
IS_VXLAN_LINK_ASSERT(link);
vxi->vxi_tos = tos;
- vxi->vxi_mask |= VXLAN_HAS_TOS;
+ vxi->ce_mask |= VXLAN_ATTR_TOS;
return 0;
}
@@ -707,7 +996,7 @@ int rtnl_link_vxlan_get_tos(struct rtnl_link *link)
IS_VXLAN_LINK_ASSERT(link);
- if (!(vxi->vxi_mask & VXLAN_HAS_TOS))
+ if (!(vxi->ce_mask & VXLAN_ATTR_TOS))
return -NLE_AGAIN;
return vxi->vxi_tos;
@@ -727,7 +1016,7 @@ int rtnl_link_vxlan_set_learning(struct rtnl_link *link, uint8_t learning)
IS_VXLAN_LINK_ASSERT(link);
vxi->vxi_learning = learning;
- vxi->vxi_mask |= VXLAN_HAS_LEARNING;
+ vxi->ce_mask |= VXLAN_ATTR_LEARNING;
return 0;
}
@@ -744,7 +1033,7 @@ int rtnl_link_vxlan_get_learning(struct rtnl_link *link)
IS_VXLAN_LINK_ASSERT(link);
- if (!(vxi->vxi_mask & VXLAN_HAS_LEARNING))
+ if (!(vxi->ce_mask & VXLAN_ATTR_LEARNING))
return -NLE_AGAIN;
return vxi->vxi_learning;
@@ -786,7 +1075,7 @@ int rtnl_link_vxlan_set_ageing(struct rtnl_link *link, uint32_t expiry)
IS_VXLAN_LINK_ASSERT(link);
vxi->vxi_ageing = expiry;
- vxi->vxi_mask |= VXLAN_HAS_AGEING;
+ vxi->ce_mask |= VXLAN_ATTR_AGEING;
return 0;
}
@@ -807,7 +1096,7 @@ int rtnl_link_vxlan_get_ageing(struct rtnl_link *link, uint32_t *expiry)
if (!expiry)
return -NLE_INVAL;
- if (vxi->vxi_mask & VXLAN_HAS_AGEING)
+ if (vxi->ce_mask & VXLAN_ATTR_AGEING)
*expiry = vxi->vxi_ageing;
else
return -NLE_AGAIN;
@@ -829,7 +1118,7 @@ int rtnl_link_vxlan_set_limit(struct rtnl_link *link, uint32_t limit)
IS_VXLAN_LINK_ASSERT(link);
vxi->vxi_limit = limit;
- vxi->vxi_mask |= VXLAN_HAS_LIMIT;
+ vxi->ce_mask |= VXLAN_ATTR_LIMIT;
return 0;
}
@@ -850,7 +1139,7 @@ int rtnl_link_vxlan_get_limit(struct rtnl_link *link, uint32_t *limit)
if (!limit)
return -NLE_INVAL;
- if (vxi->vxi_mask & VXLAN_HAS_LIMIT)
+ if (vxi->ce_mask & VXLAN_ATTR_LIMIT)
*limit = vxi->vxi_limit;
else
return -NLE_AGAIN;
@@ -866,7 +1155,7 @@ int rtnl_link_vxlan_get_limit(struct rtnl_link *link, uint32_t *limit)
* @return 0 on success or a negative error code
*/
int rtnl_link_vxlan_set_port_range(struct rtnl_link *link,
- struct ifla_vxlan_port_range *range)
+ struct ifla_vxlan_port_range *range)
{
struct vxlan_info *vxi = link->l_info;
@@ -876,7 +1165,7 @@ int rtnl_link_vxlan_set_port_range(struct rtnl_link *link,
return -NLE_INVAL;
memcpy(&vxi->vxi_port_range, range, sizeof(vxi->vxi_port_range));
- vxi->vxi_mask |= VXLAN_HAS_PORT_RANGE;
+ vxi->ce_mask |= VXLAN_ATTR_PORT_RANGE;
return 0;
}
@@ -889,7 +1178,7 @@ int rtnl_link_vxlan_set_port_range(struct rtnl_link *link,
* @return 0 on success or a negative error code
*/
int rtnl_link_vxlan_get_port_range(struct rtnl_link *link,
- struct ifla_vxlan_port_range *range)
+ struct ifla_vxlan_port_range *range)
{
struct vxlan_info *vxi = link->l_info;
@@ -898,7 +1187,7 @@ int rtnl_link_vxlan_get_port_range(struct rtnl_link *link,
if (!range)
return -NLE_INVAL;
- if (vxi->vxi_mask & VXLAN_HAS_PORT_RANGE)
+ if (vxi->ce_mask & VXLAN_ATTR_PORT_RANGE)
memcpy(range, &vxi->vxi_port_range, sizeof(*range));
else
return -NLE_AGAIN;
@@ -920,7 +1209,7 @@ int rtnl_link_vxlan_set_proxy(struct rtnl_link *link, uint8_t proxy)
IS_VXLAN_LINK_ASSERT(link);
vxi->vxi_proxy = proxy;
- vxi->vxi_mask |= VXLAN_HAS_PROXY;
+ vxi->ce_mask |= VXLAN_ATTR_PROXY;
return 0;
}
@@ -937,7 +1226,7 @@ int rtnl_link_vxlan_get_proxy(struct rtnl_link *link)
IS_VXLAN_LINK_ASSERT(link);
- if (!(vxi->vxi_mask & VXLAN_HAS_PROXY))
+ if (!(vxi->ce_mask & VXLAN_ATTR_PROXY))
return -NLE_AGAIN;
return vxi->vxi_proxy;
@@ -979,7 +1268,7 @@ int rtnl_link_vxlan_set_rsc(struct rtnl_link *link, uint8_t rsc)
IS_VXLAN_LINK_ASSERT(link);
vxi->vxi_rsc = rsc;
- vxi->vxi_mask |= VXLAN_HAS_RSC;
+ vxi->ce_mask |= VXLAN_ATTR_RSC;
return 0;
}
@@ -996,7 +1285,7 @@ int rtnl_link_vxlan_get_rsc(struct rtnl_link *link)
IS_VXLAN_LINK_ASSERT(link);
- if (!(vxi->vxi_mask & VXLAN_HAS_RSC))
+ if (!(vxi->ce_mask & VXLAN_ATTR_RSC))
return -NLE_AGAIN;
return vxi->vxi_rsc;
@@ -1038,7 +1327,7 @@ int rtnl_link_vxlan_set_l2miss(struct rtnl_link *link, uint8_t miss)
IS_VXLAN_LINK_ASSERT(link);
vxi->vxi_l2miss = miss;
- vxi->vxi_mask |= VXLAN_HAS_L2MISS;
+ vxi->ce_mask |= VXLAN_ATTR_L2MISS;
return 0;
}
@@ -1055,7 +1344,7 @@ int rtnl_link_vxlan_get_l2miss(struct rtnl_link *link)
IS_VXLAN_LINK_ASSERT(link);
- if (!(vxi->vxi_mask & VXLAN_HAS_L2MISS))
+ if (!(vxi->ce_mask & VXLAN_ATTR_L2MISS))
return -NLE_AGAIN;
return vxi->vxi_l2miss;
@@ -1097,7 +1386,7 @@ int rtnl_link_vxlan_set_l3miss(struct rtnl_link *link, uint8_t miss)
IS_VXLAN_LINK_ASSERT(link);
vxi->vxi_l3miss = miss;
- vxi->vxi_mask |= VXLAN_HAS_L3MISS;
+ vxi->ce_mask |= VXLAN_ATTR_L3MISS;
return 0;
}
@@ -1114,14 +1403,14 @@ int rtnl_link_vxlan_get_l3miss(struct rtnl_link *link)
IS_VXLAN_LINK_ASSERT(link);
- if (!(vxi->vxi_mask & VXLAN_HAS_L3MISS))
+ if (!(vxi->ce_mask & VXLAN_ATTR_L3MISS))
return -NLE_AGAIN;
return vxi->vxi_l3miss;
}
/**
- * Enable netlink IP DDR miss notifications
+ * Enable netlink IP ADDR miss notifications
* @arg link Link object
*
* @return 0 on success or a negative error code
@@ -1142,6 +1431,356 @@ int rtnl_link_vxlan_disable_l3miss(struct rtnl_link *link)
return rtnl_link_vxlan_set_l3miss(link, 0);
}
+/**
+ * Set UDP destination port to use for VXLAN
+ * @arg link Link object
+ * @arg port Destination port
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vxlan_set_port(struct rtnl_link *link, uint32_t port)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ vxi->vxi_port = htons(port);
+ vxi->ce_mask |= VXLAN_ATTR_PORT;
+
+ return 0;
+}
+
+/**
+ * Get UDP destination port to use for VXLAN
+ * @arg link Link object
+ * @arg port Pointer to store destination port
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vxlan_get_port(struct rtnl_link *link, uint32_t *port)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ if (!port)
+ return -NLE_INVAL;
+
+ if (!(vxi->ce_mask & VXLAN_ATTR_PORT))
+ return -NLE_NOATTR;
+
+ *port = ntohs(vxi->vxi_port);
+
+ return 0;
+}
+
+/**
+ * Set UDP checksum status to use for VXLAN
+ * @arg link Link object
+ * @arg csum Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vxlan_set_udp_csum(struct rtnl_link *link, uint8_t csum)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ vxi->vxi_udp_csum = csum;
+ vxi->ce_mask |= VXLAN_ATTR_UDP_CSUM;
+
+ return 0;
+}
+
+/**
+ * Get UDP checksum status to use for VXLAN
+ * @arg link Link object
+ *
+ * @return Status value on success or a negative error code
+ */
+int rtnl_link_vxlan_get_udp_csum(struct rtnl_link *link)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ if (!(vxi->ce_mask & VXLAN_ATTR_UDP_CSUM))
+ return -NLE_NOATTR;
+
+ return vxi->vxi_udp_csum;
+}
+
+/**
+ * Set skip UDP checksum transmitted over IPv6 status to use for VXLAN
+ * @arg link Link object
+ * @arg csum Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vxlan_set_udp_zero_csum6_tx(struct rtnl_link *link, uint8_t csum)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ vxi->vxi_udp_zero_csum6_tx = csum;
+ vxi->ce_mask |= VXLAN_ATTR_UDP_ZERO_CSUM6_TX;
+
+ return 0;
+}
+
+/**
+ * Get skip UDP checksum transmitted over IPv6 status to use for VXLAN
+ * @arg link Link object
+ *
+ * @return Status value on success or a negative error code
+ */
+int rtnl_link_vxlan_get_udp_zero_csum6_tx(struct rtnl_link *link)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ if (!(vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_TX))
+ return -NLE_NOATTR;
+
+ return vxi->vxi_udp_zero_csum6_tx;
+}
+
+/**
+ * Set skip UDP checksum received over IPv6 status to use for VXLAN
+ * @arg link Link object
+ * @arg csum Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vxlan_set_udp_zero_csum6_rx(struct rtnl_link *link, uint8_t csum)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ vxi->vxi_udp_zero_csum6_rx = csum;
+ vxi->ce_mask |= VXLAN_ATTR_UDP_ZERO_CSUM6_RX;
+
+ return 0;
+}
+
+/**
+ * Get skip UDP checksum received over IPv6 status to use for VXLAN
+ * @arg link Link object
+ *
+ * @return Status value on success or a negative error code
+ */
+int rtnl_link_vxlan_get_udp_zero_csum6_rx(struct rtnl_link *link)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ if (!(vxi->ce_mask & VXLAN_ATTR_UDP_ZERO_CSUM6_RX))
+ return -NLE_NOATTR;
+
+ return vxi->vxi_udp_zero_csum6_rx;
+}
+
+/**
+ * Set remote offload transmit checksum status to use for VXLAN
+ * @arg link Link object
+ * @arg csum Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vxlan_set_remcsum_tx(struct rtnl_link *link, uint8_t csum)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ vxi->vxi_remcsum_tx = csum;
+ vxi->ce_mask |= VXLAN_ATTR_REMCSUM_TX;
+
+ return 0;
+}
+
+/**
+ * Get remote offload transmit checksum status to use for VXLAN
+ * @arg link Link object
+ *
+ * @return Status value on success or a negative error code
+ */
+int rtnl_link_vxlan_get_remcsum_tx(struct rtnl_link *link)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ if (!(vxi->ce_mask & VXLAN_ATTR_REMCSUM_TX))
+ return -NLE_NOATTR;
+
+ return vxi->vxi_remcsum_tx;
+}
+
+/**
+ * Set remote offload receive checksum status to use for VXLAN
+ * @arg link Link object
+ * @arg csum Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vxlan_set_remcsum_rx(struct rtnl_link *link, uint8_t csum)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ vxi->vxi_remcsum_rx = csum;
+ vxi->ce_mask |= VXLAN_ATTR_REMCSUM_RX;
+
+ return 0;
+}
+
+/**
+ * Get remote offload receive checksum status to use for VXLAN
+ * @arg link Link object
+ *
+ * @return Status value on success or a negative error code
+ */
+int rtnl_link_vxlan_get_remcsum_rx(struct rtnl_link *link)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ if (!(vxi->ce_mask & VXLAN_ATTR_REMCSUM_RX))
+ return -NLE_NOATTR;
+
+ return vxi->vxi_remcsum_rx;
+}
+
+/**
+ * Set collect metadata status to use for VXLAN
+ * @arg link Link object
+ * @arg collect Status value
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vxlan_set_collect_metadata(struct rtnl_link *link, uint8_t collect)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ vxi->vxi_collect_metadata = collect;
+ vxi->ce_mask |= VXLAN_ATTR_COLLECT_METADATA;
+
+ return 0;
+}
+
+/**
+ * Get collect metadata status to use for VXLAN
+ * @arg link Link object
+ *
+ * @return Status value on success or a negative error code
+ */
+int rtnl_link_vxlan_get_collect_metadata(struct rtnl_link *link)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ if (!(vxi->ce_mask & VXLAN_ATTR_COLLECT_METADATA))
+ return -NLE_NOATTR;
+
+ return vxi->vxi_collect_metadata;
+}
+
+/**
+ * Set flow label to use for VXLAN
+ * @arg link Link object
+ * @arg label Destination label
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vxlan_set_label(struct rtnl_link *link, uint32_t label)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ vxi->vxi_label = htonl(label);
+ vxi->ce_mask |= VXLAN_ATTR_LABEL;
+
+ return 0;
+}
+
+/**
+ * Get flow label to use for VXLAN
+ * @arg link Link object
+ * @arg label Pointer to store destination label
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vxlan_get_label(struct rtnl_link *link, uint32_t *label)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ if (!label)
+ return -NLE_INVAL;
+
+ if (!(vxi->ce_mask & VXLAN_ATTR_LABEL))
+ return -NLE_NOATTR;
+
+ *label = ntohl(vxi->vxi_label);
+
+ return 0;
+}
+
+/**
+ * Set VXLAN flags RTNL_LINK_VXLAN_F_*
+ * @arg link Link object
+ * @flags Which flags to set
+ * @arg enable Boolean enabling or disabling flag
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_vxlan_set_flags(struct rtnl_link *link, uint32_t flags, int enable)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ if (flags & ~(RTNL_LINK_VXLAN_F_GBP | RTNL_LINK_VXLAN_F_GPE | RTNL_LINK_VXLAN_F_REMCSUM_NOPARTIAL))
+ return -NLE_INVAL;
+
+ if (enable)
+ vxi->vxi_flags |= flags;
+ else
+ vxi->vxi_flags &= ~flags;
+
+ return 0;
+}
+
+/**
+ * Get VXLAN flags RTNL_LINK_VXLAN_F_*
+ * @arg link Link object
+ * @arg out_flags Output value for flags. Must be present.
+ *
+ * @return Zero on success or a negative error code
+ */
+int rtnl_link_vxlan_get_flags(struct rtnl_link *link, uint32_t *out_flags)
+{
+ struct vxlan_info *vxi = link->l_info;
+
+ IS_VXLAN_LINK_ASSERT(link);
+
+ *out_flags = vxi->vxi_flags;
+ return 0;
+}
+
/** @} */
static void __init vxlan_init(void)
diff --git a/lib/route/link/xfrmi.c b/lib/route/link/xfrmi.c
new file mode 100644
index 00000000..5a4a5630
--- /dev/null
+++ b/lib/route/link/xfrmi.c
@@ -0,0 +1,319 @@
+/*
+ * lib/route/link/xfrmi.c XFRMI Link Info
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2019 Eyal Birger <eyal.birger@gmail.com>
+ *
+ * Based on lib/route/link/ipvti.c
+ */
+
+/**
+ * @ingroup link
+ * @defgroup xfrmi XFRMI
+ * xfrmi link module
+ *
+ * @details
+ * \b Link Type Name: "xfrmi"
+ *
+ * @route_doc{link_xfrmi, XFRMI Documentation}
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink/object.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/link/xfrmi.h>
+#include <netlink-private/route/link/api.h>
+
+#define XFRMI_ATTR_LINK (1 << 0)
+#define XFRMI_ATTR_IF_ID (1 << 1)
+
+#define XFRMI_LINK_TYPE_NAME "xfrm"
+
+struct xfrmi_info {
+ uint32_t link;
+ uint32_t if_id;
+ uint32_t xfrmi_mask;
+};
+
+static struct nla_policy xfrmi_policy[IFLA_XFRM_MAX + 1] = {
+ [IFLA_XFRM_LINK] = { .type = NLA_U32 },
+ [IFLA_XFRM_IF_ID] = { .type = NLA_U32 },
+};
+
+static int xfrmi_alloc(struct rtnl_link *link)
+{
+ struct xfrmi_info *xfrmi;
+
+ if (link->l_info)
+ memset(link->l_info, 0, sizeof(*xfrmi));
+ else {
+ xfrmi = calloc(1, sizeof(*xfrmi));
+ if (!xfrmi)
+ return -NLE_NOMEM;
+
+ link->l_info = xfrmi;
+ }
+
+ return 0;
+}
+
+static int xfrmi_parse(struct rtnl_link *link, struct nlattr *data,
+ struct nlattr *xstats)
+{
+ struct nlattr *tb[IFLA_XFRM_MAX + 1];
+ struct xfrmi_info *xfrmi;
+ int err;
+
+ NL_DBG(3, "Parsing XFRMI link info\n");
+
+ err = nla_parse_nested(tb, IFLA_XFRM_MAX, data, xfrmi_policy);
+ if (err < 0)
+ return err;
+
+ err = xfrmi_alloc(link);
+ if (err < 0)
+ return err;
+
+ xfrmi = link->l_info;
+
+ if (tb[IFLA_XFRM_LINK]) {
+ xfrmi->link = nla_get_u32(tb[IFLA_XFRM_LINK]);
+ xfrmi->xfrmi_mask |= XFRMI_ATTR_LINK;
+ }
+
+ if (tb[IFLA_XFRM_IF_ID]) {
+ xfrmi->if_id = nla_get_u32(tb[IFLA_XFRM_IF_ID]);
+ xfrmi->xfrmi_mask |= XFRMI_ATTR_IF_ID;
+ }
+
+ return 0;
+}
+
+static int xfrmi_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
+{
+ struct xfrmi_info *xfrmi = link->l_info;
+ struct nlattr *data;
+
+ data = nla_nest_start(msg, IFLA_INFO_DATA);
+ if (!data)
+ return -NLE_MSGSIZE;
+
+ if (xfrmi->xfrmi_mask & XFRMI_ATTR_LINK)
+ NLA_PUT_U32(msg, IFLA_XFRM_LINK, xfrmi->link);
+
+ if (xfrmi->xfrmi_mask & XFRMI_ATTR_IF_ID)
+ NLA_PUT_U32(msg, IFLA_XFRM_IF_ID, xfrmi->if_id);
+
+ nla_nest_end(msg, data);
+
+nla_put_failure:
+ return 0;
+}
+
+static void xfrmi_free(struct rtnl_link *link)
+{
+ struct xfrmi_info *xfrmi = link->l_info;
+
+ free(xfrmi);
+ link->l_info = NULL;
+}
+
+static void xfrmi_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ nl_dump(p, "xfrmi : %s", link->l_name);
+}
+
+static void xfrmi_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
+{
+ struct xfrmi_info *xfrmi = link->l_info;
+
+ if (xfrmi->xfrmi_mask & XFRMI_ATTR_LINK) {
+ struct rtnl_link *parent;
+ char *name;
+
+ nl_dump(p, " link ");
+
+ name = NULL;
+ parent = link_lookup(link->ce_cache, xfrmi->link);
+ if (parent)
+ name = rtnl_link_get_name(parent);
+
+ if (name)
+ nl_dump_line(p, "%s\n", name);
+ else
+ nl_dump_line(p, "%u\n", xfrmi->link);
+ }
+
+ if (xfrmi->xfrmi_mask & XFRMI_ATTR_IF_ID) {
+ nl_dump(p, " if_id ");
+ nl_dump_line(p, "%x\n", xfrmi->if_id);
+ }
+}
+
+static int xfrmi_clone(struct rtnl_link *dst, struct rtnl_link *src)
+{
+ struct xfrmi_info *xfrmi_dst, *xfrmi_src = src->l_info;
+ int err;
+
+ dst->l_info = NULL;
+
+ err = rtnl_link_set_type(dst, XFRMI_LINK_TYPE_NAME);
+ if (err < 0)
+ return err;
+
+ xfrmi_dst = dst->l_info;
+
+ if (!xfrmi_dst || !xfrmi_src)
+ BUG();
+
+ memcpy(xfrmi_dst, xfrmi_src, sizeof(struct xfrmi_info));
+
+ return 0;
+}
+
+static struct rtnl_link_info_ops xfrmi_info_ops = {
+ .io_name = XFRMI_LINK_TYPE_NAME,
+ .io_alloc = xfrmi_alloc,
+ .io_parse = xfrmi_parse,
+ .io_dump = {
+ [NL_DUMP_LINE] = xfrmi_dump_line,
+ [NL_DUMP_DETAILS] = xfrmi_dump_details,
+ },
+ .io_clone = xfrmi_clone,
+ .io_put_attrs = xfrmi_put_attrs,
+ .io_free = xfrmi_free,
+};
+
+#define IS_XFRMI_LINK_ASSERT(link) do { \
+ if ((link)->l_info_ops != &xfrmi_info_ops) { \
+ APPBUG("Link is not a xfrmi link. set type \"xfrmi\" first."); \
+ return -NLE_OPNOTSUPP; \
+ } \
+ } while(0)
+
+struct rtnl_link *rtnl_link_xfrmi_alloc(void)
+{
+ struct rtnl_link *link;
+ int err;
+
+ link = rtnl_link_alloc();
+ if (!link)
+ return NULL;
+
+ err = rtnl_link_set_type(link, XFRMI_LINK_TYPE_NAME);
+ if (err < 0) {
+ rtnl_link_put(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+/**
+ * Check if link is a XFRMI link
+ * @arg link Link object
+ *
+ * @return True if link is a IXFRMI link, otherwise 0 is returned.
+ */
+int rtnl_link_is_xfrmi(struct rtnl_link *link)
+{
+ return link->l_info_ops && !strcmp(link->l_info_ops->io_name,
+ XFRMI_LINK_TYPE_NAME);
+}
+
+/**
+ * Set XFRMI link interface index
+ * @arg link Link object
+ * @arg index interface index
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_xfrmi_set_link(struct rtnl_link *link, uint32_t index)
+{
+ struct xfrmi_info *xfrmi = link->l_info;
+
+ IS_XFRMI_LINK_ASSERT(link);
+
+ xfrmi->link = index;
+ xfrmi->xfrmi_mask |= XFRMI_ATTR_LINK;
+
+ return 0;
+}
+
+/**
+ * Get XFRMI link interface index
+ * @arg link Link object
+ * @arg out_link The output value on success
+ *
+ * @return 0 on sucess or a negative error code
+ */
+int rtnl_link_xfrmi_get_link(struct rtnl_link *link, uint32_t *out_link)
+{
+ struct xfrmi_info *xfrmi = link->l_info;
+
+ IS_XFRMI_LINK_ASSERT(link);
+
+ if (!(xfrmi->xfrmi_mask & XFRMI_ATTR_LINK))
+ return -NLE_NOATTR;
+
+ *out_link = xfrmi->link;
+ return 0;
+}
+
+/**
+ * Set XFRMI if_id
+ * @arg link Link object
+ * @arg if_id xfrm if_id
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_xfrmi_set_if_id(struct rtnl_link *link, uint32_t if_id)
+{
+ struct xfrmi_info *xfrmi = link->l_info;
+
+ IS_XFRMI_LINK_ASSERT(link);
+
+ xfrmi->if_id = if_id;
+ xfrmi->xfrmi_mask |= XFRMI_ATTR_IF_ID;
+
+ return 0;
+}
+
+/**
+ * Get XFRMI if_id
+ * @arg link Link object
+ * @arg out_if_id The output value on success
+ *
+ * @return 0 on sucess or a negative error code
+ */
+int rtnl_link_xfrmi_get_if_id(struct rtnl_link *link, uint32_t *out_if_id)
+{
+ struct xfrmi_info *xfrmi = link->l_info;
+
+ IS_XFRMI_LINK_ASSERT(link);
+
+ if (!(xfrmi->xfrmi_mask & XFRMI_ATTR_IF_ID))
+ return -NLE_NOATTR;
+
+ *out_if_id = xfrmi->if_id;
+ return 0;
+}
+
+static void __init xfrmi_init(void)
+{
+ rtnl_link_register_info(&xfrmi_info_ops);
+}
+
+static void __exit xfrmi_exit(void)
+{
+ rtnl_link_unregister_info(&xfrmi_info_ops);
+}
diff --git a/lib/route/neigh.c b/lib/route/neigh.c
index ad26b4d0..ca4f2b66 100644
--- a/lib/route/neigh.c
+++ b/lib/route/neigh.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/neigh.c Neighbours
*
@@ -35,6 +36,7 @@
* NTF_USE
* NTF_PROXY
* NTF_ROUTER
+ * NTF_SELF
* @endcode
*
* @par Neighbour Identification
@@ -67,7 +69,7 @@
* // Neighbours can then be looked up by the interface and destination
* // address:
* struct rtnl_neigh *neigh = rtnl_neigh_get(cache, ifindex, dst_addr);
- *
+ *
* // After successful usage, the object must be given back to the cache
* rtnl_neigh_put(neigh);
* @endcode
@@ -168,6 +170,7 @@
#define NEIGH_ATTR_TYPE 0x80
#define NEIGH_ATTR_PROBES 0x100
#define NEIGH_ATTR_MASTER 0x200
+#define NEIGH_ATTR_VLAN 0x400
static struct nl_cache_ops rtnl_neigh_ops;
static struct nl_object_ops neigh_obj_ops;
@@ -209,6 +212,7 @@ static void neigh_keygen(struct nl_object *obj, uint32_t *hashkey,
struct neigh_hash_key {
uint32_t n_family;
uint32_t n_ifindex;
+ uint16_t n_vlan;
char n_addr[0];
} __attribute__((packed)) *nkey;
#ifdef NL_DEBUG
@@ -232,10 +236,15 @@ static void neigh_keygen(struct nl_object *obj, uint32_t *hashkey,
return;
}
nkey->n_family = neigh->n_family;
- if (neigh->n_family == AF_BRIDGE)
- nkey->n_ifindex = neigh->n_master;
- else
+ if (neigh->n_family == AF_BRIDGE) {
+ nkey->n_vlan = neigh->n_vlan;
+ if (neigh->n_flags & NTF_SELF)
+ nkey->n_ifindex = neigh->n_ifindex;
+ else
+ nkey->n_ifindex = neigh->n_master;
+ } else
nkey->n_ifindex = neigh->n_ifindex;
+
if (addr)
memcpy(nkey->n_addr,
nl_addr_get_binary_addr(addr),
@@ -253,12 +262,12 @@ static void neigh_keygen(struct nl_object *obj, uint32_t *hashkey,
return;
}
-static int neigh_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint64_t neigh_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct rtnl_neigh *a = (struct rtnl_neigh *) _a;
struct rtnl_neigh *b = (struct rtnl_neigh *) _b;
- int diff = 0;
+ uint64_t diff = 0;
#define NEIGH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGH_ATTR_##ATTR, a, b, EXPR)
@@ -268,6 +277,7 @@ static int neigh_compare(struct nl_object *_a, struct nl_object *_b,
diff |= NEIGH_DIFF(LLADDR, nl_addr_cmp(a->n_lladdr, b->n_lladdr));
diff |= NEIGH_DIFF(DST, nl_addr_cmp(a->n_dst, b->n_dst));
diff |= NEIGH_DIFF(MASTER, a->n_master != b->n_master);
+ diff |= NEIGH_DIFF(VLAN, a->n_vlan != b->n_vlan);
if (flags & LOOSE_COMPARISON) {
diff |= NEIGH_DIFF(STATE,
@@ -285,15 +295,17 @@ static int neigh_compare(struct nl_object *_a, struct nl_object *_b,
}
static const struct trans_tbl neigh_attrs[] = {
- __ADD(NEIGH_ATTR_FLAGS, flags)
- __ADD(NEIGH_ATTR_STATE, state)
- __ADD(NEIGH_ATTR_LLADDR, lladdr)
- __ADD(NEIGH_ATTR_DST, dst)
- __ADD(NEIGH_ATTR_CACHEINFO, cacheinfo)
- __ADD(NEIGH_ATTR_IFINDEX, ifindex)
- __ADD(NEIGH_ATTR_FAMILY, family)
- __ADD(NEIGH_ATTR_TYPE, type)
- __ADD(NEIGH_ATTR_PROBES, probes)
+ __ADD(NEIGH_ATTR_FLAGS, flags),
+ __ADD(NEIGH_ATTR_STATE, state),
+ __ADD(NEIGH_ATTR_LLADDR, lladdr),
+ __ADD(NEIGH_ATTR_DST, dst),
+ __ADD(NEIGH_ATTR_CACHEINFO, cacheinfo),
+ __ADD(NEIGH_ATTR_IFINDEX, ifindex),
+ __ADD(NEIGH_ATTR_FAMILY, family),
+ __ADD(NEIGH_ATTR_TYPE, type),
+ __ADD(NEIGH_ATTR_PROBES, probes),
+ __ADD(NEIGH_ATTR_MASTER, master),
+ __ADD(NEIGH_ATTR_VLAN, vlan),
};
static char *neigh_attrs2str(int attrs, char *buf, size_t len)
@@ -306,10 +318,15 @@ static uint32_t neigh_id_attrs_get(struct nl_object *obj)
{
struct rtnl_neigh *neigh = (struct rtnl_neigh *)obj;
- if (neigh->n_family == AF_BRIDGE)
- return (NEIGH_ATTR_LLADDR | NEIGH_ATTR_FAMILY | NEIGH_ATTR_MASTER);
- else
- return (NEIGH_ATTR_IFINDEX | NEIGH_ATTR_DST | NEIGH_ATTR_FAMILY);
+ if (neigh->n_family == AF_BRIDGE) {
+ if (neigh->n_flags & NTF_SELF)
+ return (NEIGH_ATTR_LLADDR | NEIGH_ATTR_FAMILY | NEIGH_ATTR_IFINDEX |
+ ((neigh->ce_mask & NEIGH_ATTR_DST) ? NEIGH_ATTR_DST: 0) |
+ ((neigh->ce_mask & NEIGH_ATTR_VLAN) ? NEIGH_ATTR_VLAN : 0));
+ else
+ return (NEIGH_ATTR_LLADDR | NEIGH_ATTR_FAMILY | NEIGH_ATTR_MASTER | NEIGH_ATTR_VLAN);
+ } else
+ return neigh_obj_ops.oo_id_attrs;
}
static struct nla_policy neigh_policy[NDA_MAX+1] = {
@@ -375,11 +392,13 @@ int rtnl_neigh_parse(struct nlmsghdr *n, struct rtnl_neigh **result)
}
if (tb[NDA_DST]) {
- neigh->n_dst = nl_addr_alloc_attr(tb[NDA_DST], neigh->n_family);
+ neigh->n_dst = nl_addr_alloc_attr(tb[NDA_DST], AF_UNSPEC);
if (!neigh->n_dst) {
err = -NLE_NOMEM;
goto errout;
}
+ nl_addr_set_family(neigh->n_dst,
+ nl_addr_guess_family(neigh->n_dst));
neigh->ce_mask |= NEIGH_ATTR_DST;
}
@@ -390,7 +409,7 @@ int rtnl_neigh_parse(struct nlmsghdr *n, struct rtnl_neigh **result)
neigh->n_cacheinfo.nci_used = ci->ndm_used;
neigh->n_cacheinfo.nci_updated = ci->ndm_updated;
neigh->n_cacheinfo.nci_refcnt = ci->ndm_refcnt;
-
+
neigh->ce_mask |= NEIGH_ATTR_CACHEINFO;
}
@@ -399,21 +418,30 @@ int rtnl_neigh_parse(struct nlmsghdr *n, struct rtnl_neigh **result)
neigh->ce_mask |= NEIGH_ATTR_PROBES;
}
+ if (tb[NDA_VLAN]) {
+ neigh->n_vlan = nla_get_u16(tb[NDA_VLAN]);
+ neigh->ce_mask |= NEIGH_ATTR_VLAN;
+ }
+
/*
* Get the bridge index for AF_BRIDGE family entries
*/
if (neigh->n_family == AF_BRIDGE) {
- struct nl_cache *lcache = nl_cache_mngt_require_safe("route/link");
- if (lcache ) {
- struct rtnl_link *link = rtnl_link_get(lcache,
- neigh->n_ifindex);
- if (link) {
- neigh->n_master = link->l_master;
- rtnl_link_put(link);
- neigh->ce_mask |= NEIGH_ATTR_MASTER;
+ if (tb[NDA_MASTER]) {
+ neigh->n_master = nla_get_u32(tb[NDA_MASTER]);
+ neigh->ce_mask |= NEIGH_ATTR_MASTER;
+ } else {
+ struct nl_cache *lcache = nl_cache_mngt_require_safe("route/link");
+ if (lcache ) {
+ struct rtnl_link *link = rtnl_link_get(lcache,
+ neigh->n_ifindex);
+ if (link) {
+ neigh->n_master = link->l_master;
+ rtnl_link_put(link);
+ neigh->ce_mask |= NEIGH_ATTR_MASTER;
+ }
+ nl_cache_put(lcache);
}
-
- nl_cache_put(lcache);
}
}
@@ -429,7 +457,31 @@ static int neigh_request_update(struct nl_cache *c, struct nl_sock *h)
{
int family = c->c_iarg1;
- return nl_rtgen_request(h, RTM_GETNEIGH, family, NLM_F_DUMP);
+ if (family == AF_UNSPEC) {
+ return nl_rtgen_request(h, RTM_GETNEIGH, family, NLM_F_DUMP);
+ } else if (family == AF_BRIDGE) {
+ struct ifinfomsg hdr = {.ifi_family = family};
+ struct nl_msg *msg;
+ int err;
+
+ msg = nlmsg_alloc_simple(RTM_GETNEIGH, NLM_F_REQUEST | NLM_F_DUMP);
+ if (!msg)
+ return -NLE_NOMEM;
+
+ err = -NLE_MSGSIZE;
+ if (nlmsg_append(msg, &hdr, sizeof(hdr), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ err = nl_send_auto(h, msg);
+ if (err > 0)
+ err = 0;
+
+ nla_put_failure:
+ nlmsg_free(msg);
+ return err;
+ }
+
+ return -NLE_INVAL;
}
@@ -439,10 +491,14 @@ static void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p)
struct rtnl_neigh *n = (struct rtnl_neigh *) a;
struct nl_cache *link_cache;
char state[128], flags[64];
+ char buf[128];
link_cache = nl_cache_mngt_require_safe("route/link");
- if (n->n_family != AF_BRIDGE)
+ if (n->n_family != AF_UNSPEC)
+ nl_dump_line(p, "%s ", nl_af2str(n->n_family, buf, sizeof(buf)));
+
+ if (n->ce_mask & NEIGH_ATTR_DST)
nl_dump_line(p, "%s ", nl_addr2str(n->n_dst, dst, sizeof(dst)));
if (link_cache)
@@ -456,6 +512,17 @@ static void neigh_dump_line(struct nl_object *a, struct nl_dump_params *p)
nl_dump(p, "lladdr %s ",
nl_addr2str(n->n_lladdr, lladdr, sizeof(lladdr)));
+ if (n->ce_mask & NEIGH_ATTR_VLAN)
+ nl_dump(p, "vlan %d ", n->n_vlan);
+
+ if (n->ce_mask & NEIGH_ATTR_MASTER) {
+ if (link_cache)
+ nl_dump(p, "%s ", rtnl_link_i2name(link_cache, n->n_master,
+ state, sizeof(state)));
+ else
+ nl_dump(p, "%d ", n->n_master);
+ }
+
rtnl_neigh_state2str(n->n_state, state, sizeof(state));
rtnl_neigh_flags2str(n->n_flags, flags, sizeof(flags));
@@ -530,6 +597,38 @@ int rtnl_neigh_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
}
/**
+ * Build a neighbour cache including all neighbours currently configured in the kernel.
+ * @arg sock Netlink socket.
+ * @arg result Pointer to store resulting cache.
+ * @arg flags Flags to apply to cache before filling
+ *
+ * Allocates a new neighbour cache, initializes it properly and updates it
+ * to include all neighbours currently configured in the kernel.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_neigh_alloc_cache_flags(struct nl_sock *sock, struct nl_cache **result,
+ unsigned int flags)
+{
+ struct nl_cache * cache;
+ int err;
+
+ cache = nl_cache_alloc(&rtnl_neigh_ops);
+ if (!cache)
+ return -NLE_NOMEM;
+
+ nl_cache_set_flags(cache, flags);
+
+ if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
+ nl_cache_free(cache);
+ return err;
+ }
+
+ *result = cache;
+ return 0;
+}
+
+/**
* Look up a neighbour by interface index and destination address
* @arg cache neighbour cache
* @arg ifindex interface index the neighbour is on
@@ -544,6 +643,7 @@ struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex,
nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
if (neigh->n_ifindex == ifindex &&
+ neigh->n_family == dst->a_family &&
!nl_addr_cmp(neigh->n_dst, dst)) {
nl_object_get((struct nl_object *) neigh);
return neigh;
@@ -553,6 +653,32 @@ struct rtnl_neigh * rtnl_neigh_get(struct nl_cache *cache, int ifindex,
return NULL;
}
+/**
+ * Look up a neighbour by interface index, link layer address and vlan id
+ * @arg cache neighbour cache
+ * @arg ifindex interface index the neighbour is on
+ * @arg lladdr link layer address of the neighbour
+ * @arg vlan vlan id of the neighbour
+ *
+ * @return neighbour handle or NULL if no match was found.
+ */
+struct rtnl_neigh * rtnl_neigh_get_by_vlan(struct nl_cache *cache, int ifindex,
+ struct nl_addr *lladdr, int vlan)
+{
+ struct rtnl_neigh *neigh;
+
+ nl_list_for_each_entry(neigh, &cache->c_items, ce_list) {
+ if (neigh->n_ifindex == ifindex &&
+ neigh->n_vlan == vlan &&
+ neigh->n_lladdr && !nl_addr_cmp(neigh->n_lladdr, lladdr)) {
+ nl_object_get((struct nl_object *) neigh);
+ return neigh;
+ }
+ }
+
+ return NULL;
+}
+
/** @} */
/**
@@ -596,6 +722,9 @@ static int build_neigh_msg(struct rtnl_neigh *tmpl, int cmd, int flags,
if (tmpl->ce_mask & NEIGH_ATTR_LLADDR)
NLA_PUT_ADDR(msg, NDA_LLADDR, tmpl->n_lladdr);
+ if (tmpl->ce_mask & NEIGH_ATTR_VLAN)
+ NLA_PUT_U16(msg, NDA_VLAN, tmpl->n_vlan);
+
*result = msg;
return 0;
@@ -615,7 +744,7 @@ nla_put_failure:
* all relevant fields and must thus be sent out via nl_send_auto_complete()
* or supplemented as needed. \a tmpl must contain the attributes of the new
* neighbour set via \c rtnl_neigh_set_* functions.
- *
+ *
* The following attributes must be set in the template:
* - Interface index (rtnl_neigh_set_ifindex())
* - State (rtnl_neigh_set_state())
@@ -652,7 +781,7 @@ int rtnl_neigh_add(struct nl_sock *sk, struct rtnl_neigh *tmpl, int flags)
{
int err;
struct nl_msg *msg;
-
+
if ((err = rtnl_neigh_build_add_request(tmpl, flags, &msg)) < 0)
return err;
@@ -708,7 +837,7 @@ int rtnl_neigh_delete(struct nl_sock *sk, struct rtnl_neigh *neigh,
{
struct nl_msg *msg;
int err;
-
+
if ((err = rtnl_neigh_build_delete_request(neigh, flags, &msg)) < 0)
return err;
@@ -728,20 +857,25 @@ int rtnl_neigh_delete(struct nl_sock *sk, struct rtnl_neigh *neigh,
*/
static const struct trans_tbl neigh_states[] = {
- __ADD(NUD_INCOMPLETE, incomplete)
- __ADD(NUD_REACHABLE, reachable)
- __ADD(NUD_STALE, stale)
- __ADD(NUD_DELAY, delay)
- __ADD(NUD_PROBE, probe)
- __ADD(NUD_FAILED, failed)
- __ADD(NUD_NOARP, norarp)
- __ADD(NUD_PERMANENT, permanent)
+ __ADD(NUD_INCOMPLETE, incomplete),
+ __ADD(NUD_REACHABLE, reachable),
+ __ADD(NUD_STALE, stale),
+ __ADD(NUD_DELAY, delay),
+ __ADD(NUD_PROBE, probe),
+ __ADD(NUD_FAILED, failed),
+ __ADD(NUD_NOARP, noarp),
+ __ADD(NUD_PERMANENT, permanent),
+
+ /* Accept this value for backward compatibility. Originally
+ * there was a typo in the string value. This was fixed later,
+ * but we still want to successfully parse "norarp". */
+ __ADD(NUD_NOARP, norarp),
};
char * rtnl_neigh_state2str(int state, char *buf, size_t len)
{
return __flags2str(state, buf, len, neigh_states,
- ARRAY_SIZE(neigh_states));
+ ARRAY_SIZE(neigh_states) - 1);
}
int rtnl_neigh_str2state(const char *name)
@@ -757,9 +891,13 @@ int rtnl_neigh_str2state(const char *name)
*/
static const struct trans_tbl neigh_flags[] = {
- __ADD(NTF_USE, use)
- __ADD(NTF_PROXY, proxy)
- __ADD(NTF_ROUTER, router)
+ __ADD(NTF_USE, use),
+ __ADD(NTF_PROXY, proxy),
+ __ADD(NTF_ROUTER, router),
+ __ADD(NTF_SELF, self),
+ __ADD(NTF_MASTER, master),
+ __ADD(NTF_EXT_LEARNED, ext_learned),
+ __ADD(NTF_OFFLOADED, offloaded),
};
char * rtnl_neigh_flags2str(int flags, char *buf, size_t len)
@@ -908,6 +1046,30 @@ int rtnl_neigh_get_type(struct rtnl_neigh *neigh)
return -1;
}
+void rtnl_neigh_set_vlan(struct rtnl_neigh *neigh, int vlan)
+{
+ neigh->n_vlan = vlan;
+ neigh->ce_mask |= NEIGH_ATTR_VLAN;
+}
+
+int rtnl_neigh_get_vlan(struct rtnl_neigh *neigh)
+{
+ if (neigh->ce_mask & NEIGH_ATTR_VLAN)
+ return neigh->n_vlan;
+ else
+ return -1;
+}
+
+void rtnl_neigh_set_master(struct rtnl_neigh *neigh, int ifindex)
+{
+ neigh->n_master = ifindex;
+ neigh->ce_mask |= NEIGH_ATTR_MASTER;
+}
+
+int rtnl_neigh_get_master(struct rtnl_neigh *neigh) {
+ return neigh->n_master;
+}
+
/** @} */
static struct nl_object_ops neigh_obj_ops = {
diff --git a/lib/route/neightbl.c b/lib/route/neightbl.c
index f9c9c277..96ca44a1 100644
--- a/lib/route/neightbl.c
+++ b/lib/route/neightbl.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/neightbl.c neighbour tables
*
@@ -54,12 +55,12 @@ static struct nl_cache_ops rtnl_neightbl_ops;
static struct nl_object_ops neightbl_obj_ops;
/** @endcond */
-static int neightbl_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint64_t neightbl_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct rtnl_neightbl *a = (struct rtnl_neightbl *) _a;
struct rtnl_neightbl *b = (struct rtnl_neightbl *) _b;
- int diff = 0;
+ uint64_t diff = 0;
#define NT_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NEIGHTBL_ATTR_##ATTR, a, b, EXPR)
@@ -135,7 +136,7 @@ static int neightbl_msg_parser(struct nl_cache_ops *ops,
ntbl->ce_msgtype = n->nlmsg_type;
rtmsg = nlmsg_data(n);
-
+
err = nlmsg_parse(n, sizeof(*rtmsg), tb, NDTA_MAX, neightbl_policy);
if (err < 0)
goto errout;
@@ -236,7 +237,7 @@ static void neightbl_dump_line(struct nl_object *arg, struct nl_dump_params *p)
if (ntbl->nt_parms.ntp_mask & NEIGHTBLPARM_ATTR_IFINDEX) {
struct nl_cache *link_cache;
-
+
link_cache = nl_cache_mngt_require_safe("route/link");
if (link_cache) {
@@ -278,10 +279,10 @@ static void neightbl_dump_details(struct nl_object *arg, struct nl_dump_params *
ntbl->nt_config.ndtc_key_len,
ntbl->nt_config.ndtc_entry_size,
nl_msec2str(ntbl->nt_config.ndtc_last_flush,
- x, sizeof(x)));
+ x, sizeof(x)));
nl_dump_line(p, " gc threshold %u/%u/%u interval %s " \
- "chain-position %u\n",
+ "chain-position %u\n",
ntbl->nt_gc_thresh1, ntbl->nt_gc_thresh2,
ntbl->nt_gc_thresh3,
nl_msec2str(ntbl->nt_gc_interval, x, sizeof(x)),
@@ -291,33 +292,33 @@ static void neightbl_dump_details(struct nl_object *arg, struct nl_dump_params *
ntbl->nt_config.ndtc_hash_rnd,
ntbl->nt_config.ndtc_hash_mask,
nl_msec2str(ntbl->nt_config.ndtc_last_rand,
- x, sizeof(x)));
+ x, sizeof(x)));
}
if (ntbl->ce_mask & NEIGHTBL_ATTR_PARMS) {
struct rtnl_neightbl_parms *pa = &ntbl->nt_parms;
nl_dump_line(p, " refcnt %u pending-queue-limit %u " \
- "proxy-delayed-queue-limit %u\n",
+ "proxy-delayed-queue-limit %u\n",
pa->ntp_refcnt,
pa->ntp_queue_len,
pa->ntp_proxy_qlen);
nl_dump_line(p, " num-userspace-probes %u num-unicast-probes " \
- "%u num-multicast-probes %u\n",
+ "%u num-multicast-probes %u\n",
pa->ntp_app_probes,
pa->ntp_ucast_probes,
pa->ntp_mcast_probes);
nl_dump_line(p, " min-age %s base-reachable-time %s " \
- "stale-check-interval %s\n",
+ "stale-check-interval %s\n",
nl_msec2str(pa->ntp_locktime, x, sizeof(x)),
nl_msec2str(pa->ntp_base_reachable_time,
- y, sizeof(y)),
+ y, sizeof(y)),
nl_msec2str(pa->ntp_gc_stale_time, z, sizeof(z)));
nl_dump_line(p, " initial-probe-delay %s answer-delay %s " \
- "proxy-answer-delay %s\n",
+ "proxy-answer-delay %s\n",
nl_msec2str(pa->ntp_probe_delay, x, sizeof(x)),
nl_msec2str(pa->ntp_anycast_delay, y, sizeof(y)),
nl_msec2str(pa->ntp_proxy_delay, z, sizeof(z)));
@@ -334,12 +335,12 @@ static void neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
return;
nl_dump_line(p, " " \
- " lookups %" PRIu64 \
- " hits %" PRIu64 \
- " failed %" PRIu64 \
- " allocations %" PRIu64 \
- " destroys %" PRIu64 \
- "\n",
+ " lookups %" PRIu64 \
+ " hits %" PRIu64 \
+ " failed %" PRIu64 \
+ " allocations %" PRIu64 \
+ " destroys %" PRIu64 \
+ "\n",
ntbl->nt_stats.ndts_lookups,
ntbl->nt_stats.ndts_hits,
ntbl->nt_stats.ndts_res_failed,
@@ -347,18 +348,18 @@ static void neightbl_dump_stats(struct nl_object *arg, struct nl_dump_params *p)
ntbl->nt_stats.ndts_destroys);
nl_dump_line(p, " " \
- " hash-grows %" PRIu64 \
- " forced-gc-runs %" PRIu64 \
- " periodic-gc-runs %" PRIu64 \
- "\n",
+ " hash-grows %" PRIu64 \
+ " forced-gc-runs %" PRIu64 \
+ " periodic-gc-runs %" PRIu64 \
+ "\n",
ntbl->nt_stats.ndts_hash_grows,
ntbl->nt_stats.ndts_forced_gc_runs,
ntbl->nt_stats.ndts_periodic_gc_runs);
nl_dump_line(p, " " \
- " rcv-unicast-probes %" PRIu64 \
- " rcv-multicast-probes %" PRIu64 \
- "\n",
+ " rcv-unicast-probes %" PRIu64 \
+ " rcv-multicast-probes %" PRIu64 \
+ "\n",
ntbl->nt_stats.ndts_rcv_probes_ucast,
ntbl->nt_stats.ndts_rcv_probes_mcast);
}
diff --git a/lib/route/netconf.c b/lib/route/netconf.c
new file mode 100644
index 00000000..a11ad0e2
--- /dev/null
+++ b/lib/route/netconf.c
@@ -0,0 +1,584 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * lib/route/netconf.c netconf
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2017 David Ahern <dsa@cumulusnetworks.com>
+ */
+
+/**
+ * @ingroup rtnl
+ * @defgroup netconf Netconf
+ * @brief
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink/route/netconf.h>
+#include <linux/netconf.h>
+#include <linux/socket.h>
+#include <netlink/hashtable.h>
+
+/** @cond SKIP */
+#define NETCONF_ATTR_FAMILY 0x0001
+#define NETCONF_ATTR_IFINDEX 0x0002
+#define NETCONF_ATTR_RP_FILTER 0x0004
+#define NETCONF_ATTR_FWDING 0x0008
+#define NETCONF_ATTR_MC_FWDING 0x0010
+#define NETCONF_ATTR_PROXY_NEIGH 0x0020
+#define NETCONF_ATTR_IGNORE_RT_LINKDWN 0x0040
+#define NETCONF_ATTR_INPUT 0x0080
+
+struct rtnl_netconf
+{
+ NLHDR_COMMON
+
+ int family;
+ int ifindex;
+ int rp_filter;
+ int forwarding;
+ int mc_forwarding;
+ int proxy_neigh;
+ int ignore_routes_linkdown;
+ int input;
+};
+
+static struct nl_cache_ops rtnl_netconf_ops;
+static struct nl_object_ops netconf_obj_ops;
+/** @endcond */
+
+static struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = {
+ [NETCONFA_IFINDEX] = { .type = NLA_S32 },
+ [NETCONFA_FORWARDING] = { .type = NLA_S32 },
+ [NETCONFA_MC_FORWARDING] = { .type = NLA_S32 },
+ [NETCONFA_RP_FILTER] = { .type = NLA_S32 },
+ [NETCONFA_PROXY_NEIGH] = { .type = NLA_S32 },
+ [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .type = NLA_S32 },
+};
+
+static struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = {
+ [NETCONFA_IFINDEX] = { .type = NLA_S32 },
+ [NETCONFA_FORWARDING] = { .type = NLA_S32 },
+ [NETCONFA_MC_FORWARDING] = { .type = NLA_S32 },
+ [NETCONFA_PROXY_NEIGH] = { .type = NLA_S32 },
+ [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .type = NLA_S32 },
+};
+
+static struct nla_policy devconf_mpls_policy[NETCONFA_MAX+1] = {
+ [NETCONFA_IFINDEX] = { .type = NLA_S32 },
+ [NETCONFA_INPUT] = { .type = NLA_S32 },
+};
+
+static struct rtnl_netconf *rtnl_netconf_alloc(void)
+{
+ return (struct rtnl_netconf *) nl_object_alloc(&netconf_obj_ops);
+}
+
+static int netconf_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+ struct rtnl_netconf *dst = nl_object_priv(_dst);
+ struct rtnl_netconf *src = nl_object_priv(_src);
+
+ *dst = *src;
+
+ return 0;
+}
+
+static int netconf_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+ struct nlmsghdr *nlh, struct nl_parser_param *pp)
+{
+ struct nlattr *tb[NETCONFA_MAX+1], *attr;
+ struct rtnl_netconf *nc;
+ struct netconfmsg *ncm;
+ int err;
+
+ ncm = nlmsg_data(nlh);
+ switch (ncm->ncm_family) {
+ case AF_INET:
+ err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
+ devconf_ipv4_policy);
+ if (err < 0)
+ return err;
+ break;
+ case AF_INET6:
+ err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
+ devconf_ipv6_policy);
+ if (err < 0)
+ return err;
+ break;
+ case AF_MPLS:
+ err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX,
+ devconf_mpls_policy);
+ if (err < 0)
+ return err;
+ break;
+ default:
+ printf("unexpected netconf family: %d\n", ncm->ncm_family);
+ return -1;
+ }
+
+ if (!tb[NETCONFA_IFINDEX])
+ return -1;
+
+ nc = rtnl_netconf_alloc();
+ if (!nc)
+ return -NLE_NOMEM;
+
+ nc->ce_msgtype = nlh->nlmsg_type;
+ nc->family = ncm->ncm_family;
+ nc->ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]);
+
+ nc->ce_mask = NETCONF_ATTR_FAMILY | NETCONF_ATTR_IFINDEX;
+
+
+ if (tb[NETCONFA_RP_FILTER]) {
+ attr = tb[NETCONFA_RP_FILTER];
+ nc->rp_filter = nla_get_s32(attr);
+ nc->ce_mask |= NETCONF_ATTR_RP_FILTER;
+ }
+
+ if (tb[NETCONFA_FORWARDING]) {
+ attr = tb[NETCONFA_FORWARDING];
+ nc->forwarding = nla_get_s32(attr);
+ nc->ce_mask |= NETCONF_ATTR_FWDING;
+ }
+
+ if (tb[NETCONFA_MC_FORWARDING]) {
+ attr = tb[NETCONFA_MC_FORWARDING];
+ nc->mc_forwarding = nla_get_s32(attr);
+ nc->ce_mask |= NETCONF_ATTR_MC_FWDING;
+ }
+
+ if (tb[NETCONFA_PROXY_NEIGH]) {
+ attr = tb[NETCONFA_PROXY_NEIGH];
+ nc->proxy_neigh = nla_get_s32(attr);
+ nc->ce_mask |= NETCONF_ATTR_PROXY_NEIGH;
+ }
+
+ if (tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]) {
+ attr = tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN];
+ nc->ignore_routes_linkdown = nla_get_s32(attr);
+ nc->ce_mask |= NETCONF_ATTR_IGNORE_RT_LINKDWN;
+ }
+
+ if (tb[NETCONFA_INPUT]) {
+ attr = tb[NETCONFA_INPUT];
+ nc->input = nla_get_s32(attr);
+ nc->ce_mask |= NETCONF_ATTR_INPUT;
+ }
+
+ err = pp->pp_cb((struct nl_object *) nc, pp);
+
+ rtnl_netconf_put(nc);
+ return err;
+}
+
+static int netconf_request_update(struct nl_cache *cache, struct nl_sock *sk)
+{
+ struct netconfmsg nc = {
+ .ncm_family = cache->c_iarg1,
+ };
+
+ return nl_send_simple(sk, RTM_GETNETCONF, NLM_F_DUMP, &nc, sizeof(nc));
+}
+
+static void netconf_dump_line(struct nl_object *obj, struct nl_dump_params *p)
+{
+ struct rtnl_netconf *nc = (struct rtnl_netconf *) obj;
+ struct nl_cache *link_cache;
+ char buf[64];
+
+ switch(nc->family) {
+ case AF_INET:
+ nl_dump(p, "ipv4 ");
+ break;
+ case AF_INET6:
+ nl_dump(p, "ipv6 ");
+ break;
+ case AF_MPLS:
+ nl_dump(p, "mpls ");
+ break;
+ default:
+ return;
+ }
+
+ switch(nc->ifindex) {
+ case NETCONFA_IFINDEX_ALL:
+ nl_dump(p, "all ");
+ break;
+ case NETCONFA_IFINDEX_DEFAULT:
+ nl_dump(p, "default ");
+ break;
+ default:
+ link_cache = nl_cache_mngt_require_safe("route/link");
+ if (link_cache) {
+ nl_dump(p, "dev %s ",
+ rtnl_link_i2name(link_cache, nc->ifindex,
+ buf, sizeof(buf)));
+ nl_cache_put(link_cache);
+ } else
+ nl_dump(p, "dev %d ", nc->ifindex);
+ }
+
+ if (nc->ce_mask & NETCONF_ATTR_FWDING) {
+ nl_dump(p, "forwarding %s ",
+ nc->forwarding ? "on" : "off");
+ }
+
+ if (nc->ce_mask & NETCONF_ATTR_RP_FILTER) {
+ if (nc->rp_filter == 0)
+ nl_dump(p, "rp_filter off ");
+ else if (nc->rp_filter == 1)
+ nl_dump(p, "rp_filter strict ");
+ else if (nc->rp_filter == 2)
+ nl_dump(p, "rp_filter loose ");
+ else
+ nl_dump(p, "rp_filter unknown-mode ");
+ }
+
+ if (nc->ce_mask & NETCONF_ATTR_MC_FWDING) {
+ nl_dump(p, "mc_forwarding %s ",
+ nc->mc_forwarding ? "on" : "off");
+ }
+
+ if (nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH)
+ nl_dump(p, "proxy_neigh %d ", nc->proxy_neigh);
+
+ if (nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN) {
+ nl_dump(p, "ignore_routes_with_linkdown %s ",
+ nc->ignore_routes_linkdown ? "on" : "off");
+ }
+
+ if (nc->ce_mask & NETCONF_ATTR_INPUT)
+ nl_dump(p, "input %s ", nc->input ? "on" : "off");
+
+ nl_dump(p, "\n");
+}
+
+static const struct trans_tbl netconf_attrs[] = {
+ __ADD(NETCONF_ATTR_FAMILY, family),
+ __ADD(NETCONF_ATTR_IFINDEX, ifindex),
+ __ADD(NETCONF_ATTR_RP_FILTER, rp_filter),
+ __ADD(NETCONF_ATTR_FWDING, forwarding),
+ __ADD(NETCONF_ATTR_MC_FWDING, mc_forwarding),
+ __ADD(NETCONF_ATTR_PROXY_NEIGH, proxy_neigh),
+ __ADD(NETCONF_ATTR_IGNORE_RT_LINKDWN, ignore_routes_with_linkdown),
+ __ADD(NETCONF_ATTR_INPUT, input),
+};
+
+static char *netconf_attrs2str(int attrs, char *buf, size_t len)
+{
+ return __flags2str(attrs, buf, len, netconf_attrs,
+ ARRAY_SIZE(netconf_attrs));
+}
+
+static void netconf_keygen(struct nl_object *obj, uint32_t *hashkey,
+ uint32_t table_sz)
+{
+ struct rtnl_netconf *nc = (struct rtnl_netconf *) obj;
+ unsigned int nckey_sz;
+ struct nc_hash_key {
+ int nc_family;
+ int nc_index;
+ } __attribute__((packed)) nckey;
+
+ nckey_sz = sizeof(nckey);
+ nckey.nc_family = nc->family;
+ nckey.nc_index = nc->ifindex;
+
+ *hashkey = nl_hash(&nckey, nckey_sz, 0) % table_sz;
+
+ NL_DBG(5, "netconf %p key (dev %d fam %d) keysz %d, hash 0x%x\n",
+ nc, nckey.nc_index, nckey.nc_family, nckey_sz, *hashkey);
+}
+
+static uint64_t netconf_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
+{
+ struct rtnl_netconf *a = (struct rtnl_netconf *) _a;
+ struct rtnl_netconf *b = (struct rtnl_netconf *) _b;
+ uint64_t diff = 0;
+
+#define NETCONF_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NETCONF_ATTR_##ATTR, a, b, EXPR)
+
+ diff |= NETCONF_DIFF(FAMILY, a->family != b->family);
+ diff |= NETCONF_DIFF(IFINDEX, a->ifindex != b->ifindex);
+ diff |= NETCONF_DIFF(RP_FILTER, a->rp_filter != b->rp_filter);
+ diff |= NETCONF_DIFF(FWDING, a->forwarding != b->forwarding);
+ diff |= NETCONF_DIFF(MC_FWDING, a->mc_forwarding != b->mc_forwarding);
+ diff |= NETCONF_DIFF(PROXY_NEIGH, a->proxy_neigh != b->proxy_neigh);
+ diff |= NETCONF_DIFF(IGNORE_RT_LINKDWN,
+ a->ignore_routes_linkdown != b->ignore_routes_linkdown);
+ diff |= NETCONF_DIFF(INPUT, a->input != b->input);
+
+#undef NETCONF_DIFF
+
+ return diff;
+}
+
+static int netconf_update(struct nl_object *old_obj, struct nl_object *new_obj)
+{
+ struct rtnl_netconf *new_nc = (struct rtnl_netconf *) new_obj;
+ struct rtnl_netconf *old_nc = (struct rtnl_netconf *) old_obj;
+ int action = new_obj->ce_msgtype;
+
+ switch(action) {
+ case RTM_NEWNETCONF:
+ if (new_nc->family != old_nc->family ||
+ new_nc->ifindex != old_nc->ifindex)
+ return -NLE_OPNOTSUPP;
+
+ if (new_nc->ce_mask & NETCONF_ATTR_RP_FILTER)
+ old_nc->rp_filter = new_nc->rp_filter;
+ if (new_nc->ce_mask & NETCONF_ATTR_FWDING)
+ old_nc->forwarding = new_nc->forwarding;
+ if (new_nc->ce_mask & NETCONF_ATTR_MC_FWDING)
+ old_nc->mc_forwarding = new_nc->mc_forwarding;
+ if (new_nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH)
+ old_nc->proxy_neigh = new_nc->proxy_neigh;
+ if (new_nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN)
+ old_nc->ignore_routes_linkdown = new_nc->ignore_routes_linkdown;
+
+ break;
+ default:
+ return -NLE_OPNOTSUPP;
+ }
+
+ return NLE_SUCCESS;
+}
+
+/**
+ * @name Cache Management
+ * @{
+ */
+
+int rtnl_netconf_alloc_cache(struct nl_sock *sk, struct nl_cache **result)
+{
+ return nl_cache_alloc_and_fill(&rtnl_netconf_ops, sk, result);
+}
+
+/**
+ * Search netconf in cache
+ * @arg cache netconf cache
+ * @arg family Address family of interest
+ * @arg ifindex Interface index of interest
+ *
+ * Searches netconf cache previously allocated with rtnl_netconf_alloc_cache()
+ * for given index and family
+ *
+ * The reference counter is incremented before returning the netconf entry,
+ * therefore the reference must be given back with rtnl_netconf_put() after
+ * usage.
+ *
+ * @return netconf object or NULL if no match was found.
+ */
+struct rtnl_netconf *rtnl_netconf_get_by_idx(struct nl_cache *cache, int family,
+ int ifindex)
+{
+ struct rtnl_netconf *nc;
+
+ if (!ifindex || !family || cache->c_ops != &rtnl_netconf_ops)
+ return NULL;
+
+ nl_list_for_each_entry(nc, &cache->c_items, ce_list) {
+ if (nc->ifindex == ifindex &&
+ nc->family == family) {
+ nl_object_get((struct nl_object *) nc);
+ return nc;
+ }
+ }
+
+ return NULL;
+}
+
+void rtnl_netconf_put(struct rtnl_netconf *nc)
+{
+ nl_object_put((struct nl_object *) nc);
+}
+
+/**
+ * Search netconf in cache
+ * @arg cache netconf cache
+ * @arg family Address family of interest
+ *
+ * Searches netconf cache previously allocated with rtnl_netconf_alloc_cache()
+ * for "all" netconf settings for given family
+ *
+ * The reference counter is incremented before returning the netconf entry,
+ * therefore the reference must be given back with rtnl_netconf_put() after
+ * usage.
+ *
+ * @return netconf object or NULL if no match was found.
+ */
+struct rtnl_netconf *rtnl_netconf_get_all(struct nl_cache *cache, int family)
+{
+ return rtnl_netconf_get_by_idx(cache, family, NETCONFA_IFINDEX_ALL);
+}
+
+/**
+ * Search netconf in cache
+ * @arg cache netconf cache
+ * @arg family Address family of interest
+ *
+ * Searches netconf cache previously allocated with rtnl_netconf_alloc_cache()
+ * for "default" netconf settings for given family
+ *
+ * The reference counter is incremented before returning the netconf entry,
+ * therefore the reference must be given back with rtnl_netconf_put() after
+ * usage.
+ *
+ * @return netconf object or NULL if no match was found.
+ */
+struct rtnl_netconf *rtnl_netconf_get_default(struct nl_cache *cache, int family)
+{
+ return rtnl_netconf_get_by_idx(cache, family, NETCONFA_IFINDEX_DEFAULT);
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+int rtnl_netconf_get_family(struct rtnl_netconf *nc, int *val)
+{
+ if (!nc)
+ return -NLE_INVAL;
+ if (!(nc->ce_mask & NETCONF_ATTR_FAMILY))
+ return -NLE_MISSING_ATTR;
+ if (val)
+ *val = nc->family;
+ return 0;
+}
+int rtnl_netconf_get_ifindex(struct rtnl_netconf *nc, int *val)
+{
+ if (!nc)
+ return -NLE_INVAL;
+ if (!(nc->ce_mask & NETCONF_ATTR_IFINDEX))
+ return -NLE_MISSING_ATTR;
+ if (val)
+ *val = nc->ifindex;
+ return 0;
+}
+int rtnl_netconf_get_forwarding(struct rtnl_netconf *nc, int *val)
+{
+ if (!nc)
+ return -NLE_INVAL;
+ if (!(nc->ce_mask & NETCONF_ATTR_FWDING))
+ return -NLE_MISSING_ATTR;
+ if (val)
+ *val = nc->forwarding;
+ return 0;
+}
+int rtnl_netconf_get_mc_forwarding(struct rtnl_netconf *nc, int *val)
+{
+ if (!nc)
+ return -NLE_INVAL;
+ if (!(nc->ce_mask & NETCONF_ATTR_MC_FWDING))
+ return -NLE_MISSING_ATTR;
+ if (val)
+ *val = nc->mc_forwarding;
+ return 0;
+}
+int rtnl_netconf_get_rp_filter(struct rtnl_netconf *nc, int *val)
+{
+ if (!nc)
+ return -NLE_INVAL;
+ if (!(nc->ce_mask & NETCONF_ATTR_RP_FILTER))
+ return -NLE_MISSING_ATTR;
+ if (val)
+ *val = nc->rp_filter;
+ return 0;
+}
+int rtnl_netconf_get_proxy_neigh(struct rtnl_netconf *nc, int *val)
+{
+ if (!nc)
+ return -NLE_INVAL;
+ if (!(nc->ce_mask & NETCONF_ATTR_PROXY_NEIGH))
+ return -NLE_MISSING_ATTR;
+ if (val)
+ *val = nc->proxy_neigh;
+ return 0;
+}
+int rtnl_netconf_get_ignore_routes_linkdown(struct rtnl_netconf *nc, int *val)
+{
+ if (!nc)
+ return -NLE_INVAL;
+ if (!(nc->ce_mask & NETCONF_ATTR_IGNORE_RT_LINKDWN))
+ return -NLE_MISSING_ATTR;
+ if (val)
+ *val = nc->ignore_routes_linkdown;
+ return 0;
+}
+int rtnl_netconf_get_input(struct rtnl_netconf *nc, int *val)
+{
+ if (!nc)
+ return -NLE_INVAL;
+ if (!(nc->ce_mask & NETCONF_ATTR_INPUT))
+ return -NLE_MISSING_ATTR;
+ if (val)
+ *val = nc->input;
+ return 0;
+}
+
+
+/** @} */
+
+static struct nl_object_ops netconf_obj_ops = {
+ .oo_name = "route/netconf",
+ .oo_size = sizeof(struct rtnl_netconf),
+ .oo_clone = netconf_clone,
+ .oo_dump = {
+ [NL_DUMP_LINE] = netconf_dump_line,
+ [NL_DUMP_DETAILS] = netconf_dump_line,
+ },
+ .oo_compare = netconf_compare,
+ .oo_keygen = netconf_keygen,
+ .oo_update = netconf_update,
+ .oo_attrs2str = netconf_attrs2str,
+ .oo_id_attrs = (NETCONF_ATTR_FAMILY |
+ NETCONF_ATTR_IFINDEX)
+};
+
+static struct nl_af_group netconf_groups[] = {
+ { AF_INET, RTNLGRP_IPV4_NETCONF },
+ { AF_INET6, RTNLGRP_IPV6_NETCONF },
+ { AF_MPLS, RTNLGRP_MPLS_NETCONF },
+ { END_OF_GROUP_LIST },
+};
+
+static struct nl_cache_ops rtnl_netconf_ops = {
+ .co_name = "route/netconf",
+ .co_hdrsize = sizeof(struct netconfmsg),
+ .co_msgtypes = {
+ { RTM_NEWNETCONF, NL_ACT_NEW, "new" },
+ { RTM_DELNETCONF, NL_ACT_DEL, "del" },
+ { RTM_GETNETCONF, NL_ACT_GET, "get" },
+ END_OF_MSGTYPES_LIST,
+ },
+ .co_protocol = NETLINK_ROUTE,
+ .co_groups = netconf_groups,
+ .co_request_update = netconf_request_update,
+ .co_msg_parser = netconf_msg_parser,
+ .co_obj_ops = &netconf_obj_ops,
+};
+
+static void __init netconf_init(void)
+{
+ nl_cache_mngt_register(&rtnl_netconf_ops);
+}
+
+static void __exit netconf_exit(void)
+{
+ nl_cache_mngt_unregister(&rtnl_netconf_ops);
+}
+
+/** @} */
diff --git a/lib/route/nexthop.c b/lib/route/nexthop.c
index d3ca4991..7a9904c9 100644
--- a/lib/route/nexthop.c
+++ b/lib/route/nexthop.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/nexthop.c Routing Nexthop
*
@@ -16,6 +17,7 @@
*/
#include <netlink-private/netlink.h>
+#include <netlink-private/route/nexthop-encap.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/rtnl.h>
@@ -27,6 +29,9 @@
#define NH_ATTR_IFINDEX 0x000004
#define NH_ATTR_GATEWAY 0x000008
#define NH_ATTR_REALMS 0x000010
+#define NH_ATTR_NEWDST 0x000020
+#define NH_ATTR_VIA 0x000040
+#define NH_ATTR_ENCAP 0x000080
/** @endcond */
/**
@@ -69,12 +74,39 @@ struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src)
}
}
+ if (src->rtnh_newdst) {
+ nh->rtnh_newdst = nl_addr_clone(src->rtnh_newdst);
+ if (!nh->rtnh_newdst) {
+ nl_addr_put(nh->rtnh_gateway);
+ free(nh);
+ return NULL;
+ }
+ }
+
+ if (src->rtnh_via) {
+ nh->rtnh_via = nl_addr_clone(src->rtnh_via);
+ if (!nh->rtnh_via) {
+ nl_addr_put(nh->rtnh_gateway);
+ nl_addr_put(nh->rtnh_newdst);
+ free(nh);
+ return NULL;
+ }
+ }
+
return nh;
}
void rtnl_route_nh_free(struct rtnl_nexthop *nh)
{
nl_addr_put(nh->rtnh_gateway);
+ nl_addr_put(nh->rtnh_newdst);
+ nl_addr_put(nh->rtnh_via);
+ if (nh->rtnh_encap) {
+ if (nh->rtnh_encap->ops && nh->rtnh_encap->ops->destructor)
+ nh->rtnh_encap->ops->destructor(nh->rtnh_encap->priv);
+ free(nh->rtnh_encap->priv);
+ free(nh->rtnh_encap);
+ }
free(nh);
}
@@ -92,6 +124,12 @@ int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
diff |= NH_DIFF(REALMS, a->rtnh_realms != b->rtnh_realms);
diff |= NH_DIFF(GATEWAY, nl_addr_cmp(a->rtnh_gateway,
b->rtnh_gateway));
+ diff |= NH_DIFF(NEWDST, nl_addr_cmp(a->rtnh_newdst,
+ b->rtnh_newdst));
+ diff |= NH_DIFF(VIA, nl_addr_cmp(a->rtnh_via,
+ b->rtnh_via));
+ diff |= NH_DIFF(ENCAP, nh_encap_compare(a->rtnh_encap,
+ b->rtnh_encap));
if (loose)
diff |= NH_DIFF(FLAGS,
@@ -111,8 +149,19 @@ static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
link_cache = nl_cache_mngt_require_safe("route/link");
+ if (nh->ce_mask & NH_ATTR_ENCAP)
+ nh_encap_dump(nh->rtnh_encap, dp);
+
+ if (nh->ce_mask & NH_ATTR_NEWDST)
+ nl_dump(dp, "as to %s ",
+ nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf)));
+
nl_dump(dp, "via");
+ if (nh->ce_mask & NH_ATTR_VIA)
+ nl_dump(dp, " %s",
+ nl_addr2str(nh->rtnh_via, buf, sizeof(buf)));
+
if (nh->ce_mask & NH_ATTR_GATEWAY)
nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway,
buf, sizeof(buf)));
@@ -142,6 +191,17 @@ static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
nl_dump(dp, "nexthop");
+ if (nh->ce_mask & NH_ATTR_ENCAP)
+ nh_encap_dump(nh->rtnh_encap, dp);
+
+ if (nh->ce_mask & NH_ATTR_NEWDST)
+ nl_dump(dp, " as to %s",
+ nl_addr2str(nh->rtnh_newdst, buf, sizeof(buf)));
+
+ if (nh->ce_mask & NH_ATTR_VIA)
+ nl_dump(dp, " via %s",
+ nl_addr2str(nh->rtnh_via, buf, sizeof(buf)));
+
if (nh->ce_mask & NH_ATTR_GATEWAY)
nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway,
buf, sizeof(buf)));
@@ -190,6 +250,24 @@ void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
}
}
+void nh_set_encap(struct rtnl_nexthop *nh, struct rtnl_nh_encap *rtnh_encap)
+{
+ if (nh->rtnh_encap) {
+ if (nh->rtnh_encap->ops && nh->rtnh_encap->ops->destructor)
+ nh->rtnh_encap->ops->destructor(nh->rtnh_encap->priv);
+ free(nh->rtnh_encap->priv);
+ free(nh->rtnh_encap);
+ }
+
+ if (rtnh_encap) {
+ nh->rtnh_encap = rtnh_encap;
+ nh->ce_mask |= NH_ATTR_ENCAP;
+ } else {
+ nh->rtnh_encap = NULL;
+ nh->ce_mask &= ~NH_ATTR_ENCAP;
+ }
+}
+
/**
* @name Attributes
* @{
@@ -269,6 +347,60 @@ uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
return nh->rtnh_realms;
}
+int rtnl_route_nh_set_newdst(struct rtnl_nexthop *nh, struct nl_addr *addr)
+{
+ struct nl_addr *old = nh->rtnh_newdst;
+
+ if (!nl_addr_valid(nl_addr_get_binary_addr(addr),
+ nl_addr_get_len(addr)))
+ return -NLE_INVAL;
+
+ if (addr) {
+ nh->rtnh_newdst = nl_addr_get(addr);
+ nh->ce_mask |= NH_ATTR_NEWDST;
+ } else {
+ nh->ce_mask &= ~NH_ATTR_NEWDST;
+ nh->rtnh_newdst = NULL;
+ }
+
+ if (old)
+ nl_addr_put(old);
+
+ return 0;
+}
+
+struct nl_addr *rtnl_route_nh_get_newdst(struct rtnl_nexthop *nh)
+{
+ return nh->rtnh_newdst;
+}
+
+int rtnl_route_nh_set_via(struct rtnl_nexthop *nh, struct nl_addr *addr)
+{
+ struct nl_addr *old = nh->rtnh_via;
+
+ if (!nl_addr_valid(nl_addr_get_binary_addr(addr),
+ nl_addr_get_len(addr)))
+ return -NLE_INVAL;
+
+ if (addr) {
+ nh->rtnh_via = nl_addr_get(addr);
+ nh->ce_mask |= NH_ATTR_VIA;
+ } else {
+ nh->ce_mask &= ~NH_ATTR_VIA;
+ nh->rtnh_via= NULL;
+ }
+
+ if (old)
+ nl_addr_put(old);
+
+ return 0;
+}
+
+struct nl_addr *rtnl_route_nh_get_via(struct rtnl_nexthop *nh)
+{
+ return nh->rtnh_via;
+}
+
/** @} */
/**
@@ -277,9 +409,9 @@ uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
*/
static const struct trans_tbl nh_flags[] = {
- __ADD(RTNH_F_DEAD, dead)
- __ADD(RTNH_F_PERVASIVE, pervasive)
- __ADD(RTNH_F_ONLINK, onlink)
+ __ADD(RTNH_F_DEAD, dead),
+ __ADD(RTNH_F_PERVASIVE, pervasive),
+ __ADD(RTNH_F_ONLINK, onlink),
};
char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
diff --git a/lib/route/nexthop_encap.c b/lib/route/nexthop_encap.c
new file mode 100644
index 00000000..21f647a7
--- /dev/null
+++ b/lib/route/nexthop_encap.c
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/types.h>
+#include <netlink-private/route/nexthop-encap.h>
+#include <linux/lwtunnel.h>
+
+static struct lwtunnel_encap_type {
+ const char *name;
+ struct nh_encap_ops *ops;
+} lwtunnel_encap_types[__LWTUNNEL_ENCAP_MAX] = {
+ [LWTUNNEL_ENCAP_NONE] = { .name = "none" },
+ [LWTUNNEL_ENCAP_MPLS] = { .name = "mpls", .ops = &mpls_encap_ops },
+ [LWTUNNEL_ENCAP_IP] = { .name = "ip" },
+ [LWTUNNEL_ENCAP_IP6] = { .name = "ip6" },
+ [LWTUNNEL_ENCAP_ILA] = { .name = "ila" },
+ [LWTUNNEL_ENCAP_BPF] = { .name = "bpf" },
+};
+
+static const char *nh_encap_type2str(unsigned int type)
+{
+ const char *name;
+
+ if (type > LWTUNNEL_ENCAP_MAX)
+ return "unknown";
+
+ name = lwtunnel_encap_types[type].name;
+
+ return name ? name : "unknown";
+}
+
+void nh_encap_dump(struct rtnl_nh_encap *rtnh_encap, struct nl_dump_params *dp)
+{
+ nl_dump(dp, " encap %s ",
+ nh_encap_type2str(rtnh_encap->ops->encap_type));
+
+ if (rtnh_encap->ops && rtnh_encap->ops->dump)
+ rtnh_encap->ops->dump(rtnh_encap->priv, dp);
+}
+
+int nh_encap_build_msg(struct nl_msg *msg, struct rtnl_nh_encap *rtnh_encap)
+{
+ struct nlattr *encap;
+ int err;
+
+ if (!rtnh_encap->ops || !rtnh_encap->ops->build_msg) {
+ NL_DBG(2, "Nexthop encap type not implemented\n");
+ return -NLE_INVAL;
+ }
+
+ NLA_PUT_U16(msg, RTA_ENCAP_TYPE, rtnh_encap->ops->encap_type);
+
+ encap = nla_nest_start(msg, RTA_ENCAP);
+ if (!encap)
+ goto nla_put_failure;
+
+ err = rtnh_encap->ops->build_msg(msg, rtnh_encap->priv);
+ if (err)
+ return err;
+
+ nla_nest_end(msg, encap);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+int nh_encap_parse_msg(struct nlattr *encap, struct nlattr *encap_type,
+ struct rtnl_nexthop *rtnh)
+{
+ uint16_t e_type = nla_get_u16(encap_type);
+
+ if (e_type == LWTUNNEL_ENCAP_NONE) {
+ NL_DBG(2, "RTA_ENCAP_TYPE should not be LWTUNNEL_ENCAP_NONE\n");
+ return -NLE_INVAL;
+ }
+ if (e_type > LWTUNNEL_ENCAP_MAX) {
+ NL_DBG(2, "Unknown RTA_ENCAP_TYPE: %d\n", e_type);
+ return -NLE_INVAL;
+ }
+
+ if (!lwtunnel_encap_types[e_type].ops) {
+ NL_DBG(2, "RTA_ENCAP_TYPE %s is not implemented\n",
+ lwtunnel_encap_types[e_type].name);
+ return -NLE_MSGTYPE_NOSUPPORT;
+ }
+
+ return lwtunnel_encap_types[e_type].ops->parse_msg(encap, rtnh);
+}
+
+int nh_encap_compare(struct rtnl_nh_encap *a, struct rtnl_nh_encap *b)
+{
+ if (!a && !b)
+ return 0;
+
+ if ((a && !b) || (!a && b) || (a->ops != b->ops))
+ return 1;
+
+ if (!a->ops || !a->ops->compare)
+ return 0;
+
+ return a->ops->compare(a->priv, b->priv);
+}
diff --git a/lib/route/nh_encap_mpls.c b/lib/route/nh_encap_mpls.c
new file mode 100644
index 00000000..081661e6
--- /dev/null
+++ b/lib/route/nh_encap_mpls.c
@@ -0,0 +1,135 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/types.h>
+#include <netlink-private/route/nexthop-encap.h>
+#include <netlink/route/nexthop.h>
+#include <linux/mpls_iptunnel.h>
+#include <linux/lwtunnel.h>
+
+struct mpls_iptunnel_encap {
+ struct nl_addr *dst;
+ uint8_t ttl;
+};
+
+static void mpls_encap_dump(void *priv, struct nl_dump_params *dp)
+{
+ struct mpls_iptunnel_encap *encap_info = priv;
+ char buf[256];
+
+ nl_dump(dp, "%s ", nl_addr2str(encap_info->dst, buf, sizeof(buf)));
+
+ if (encap_info->ttl)
+ nl_dump(dp, "ttl %u ", encap_info->ttl);
+}
+
+static int mpls_encap_build_msg(struct nl_msg *msg, void *priv)
+{
+ struct mpls_iptunnel_encap *encap_info = priv;
+
+ NLA_PUT_ADDR(msg, MPLS_IPTUNNEL_DST, encap_info->dst);
+ if (encap_info->ttl)
+ NLA_PUT_U8(msg, MPLS_IPTUNNEL_TTL, encap_info->ttl);
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+static void mpls_encap_destructor(void *priv)
+{
+ struct mpls_iptunnel_encap *encap_info = priv;
+
+ nl_addr_put(encap_info->dst);
+}
+
+static struct nla_policy mpls_encap_policy[MPLS_IPTUNNEL_MAX + 1] = {
+ [MPLS_IPTUNNEL_DST] = { .type = NLA_U32 },
+ [MPLS_IPTUNNEL_TTL] = { .type = NLA_U8 },
+};
+
+static int mpls_encap_parse_msg(struct nlattr *nla, struct rtnl_nexthop *nh)
+{
+ struct nlattr *tb[MPLS_IPTUNNEL_MAX + 1];
+ struct nl_addr *labels;
+ uint8_t ttl = 0;
+ int err;
+
+
+ err = nla_parse_nested(tb, MPLS_IPTUNNEL_MAX, nla, mpls_encap_policy);
+ if (err)
+ return err;
+
+ if (!tb[MPLS_IPTUNNEL_DST])
+ return -NLE_INVAL;
+
+ labels = nl_addr_alloc_attr(tb[MPLS_IPTUNNEL_DST], AF_MPLS);
+ if (!labels)
+ return -NLE_NOMEM;
+
+ if (tb[MPLS_IPTUNNEL_TTL])
+ ttl = nla_get_u8(tb[MPLS_IPTUNNEL_TTL]);
+
+ err = rtnl_route_nh_encap_mpls(nh, labels, ttl);
+
+ nl_addr_put(labels);
+
+ return err;
+}
+
+static int mpls_encap_compare(void *_a, void *_b)
+{
+ struct mpls_iptunnel_encap *a = _a;
+ struct mpls_iptunnel_encap *b = _b;
+ int diff = 0;
+
+ diff |= (a->ttl != b->ttl);
+ diff |= nl_addr_cmp(a->dst, b->dst);
+
+ return diff;
+}
+
+struct nh_encap_ops mpls_encap_ops = {
+ .encap_type = LWTUNNEL_ENCAP_MPLS,
+ .build_msg = mpls_encap_build_msg,
+ .parse_msg = mpls_encap_parse_msg,
+ .compare = mpls_encap_compare,
+ .dump = mpls_encap_dump,
+ .destructor = mpls_encap_destructor,
+};
+
+int rtnl_route_nh_encap_mpls(struct rtnl_nexthop *nh,
+ struct nl_addr *addr,
+ uint8_t ttl)
+{
+ struct mpls_iptunnel_encap *mpls_encap;
+ struct rtnl_nh_encap *rtnh_encap;
+
+ if (!addr)
+ return -NLE_INVAL;
+
+ if (!nl_addr_valid(nl_addr_get_binary_addr(addr),
+ nl_addr_get_len(addr)))
+ return -NLE_INVAL;
+
+ rtnh_encap = calloc(1, sizeof(*rtnh_encap));
+ if (!rtnh_encap)
+ return -NLE_NOMEM;
+
+ mpls_encap = calloc(1, sizeof(*mpls_encap));
+ if (!mpls_encap) {
+ free(rtnh_encap);
+ return -NLE_NOMEM;
+ }
+
+ mpls_encap->dst = nl_addr_get(addr);
+ mpls_encap->ttl = ttl;
+
+ rtnh_encap->priv = mpls_encap;
+ rtnh_encap->ops = &mpls_encap_ops;
+
+ nh_set_encap(nh, rtnh_encap);
+
+ return 0;
+}
diff --git a/lib/route/pktloc.c b/lib/route/pktloc.c
index 27d63be2..9462c6e2 100644
--- a/lib/route/pktloc.c
+++ b/lib/route/pktloc.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/pktloc.c Packet Location Aliasing
*
@@ -101,13 +102,15 @@ static int read_pktlocs(void)
/* if stat fails, just try to read the file */
if (stat(path, &st) == 0) {
/* Don't re-read file if file is unchanged */
- if (last_read == st.st_mtime)
- return 0;
+ if (last_read == st.st_mtime) {
+ err = 0;
+ goto errout;
+ }
}
NL_DBG(2, "Reading packet location file \"%s\"\n", path);
- if (!(fd = fopen(path, "r"))) {
+ if (!(fd = fopen(path, "re"))) {
err = -NLE_PKTLOC_FILE;
goto errout;
}
diff --git a/lib/route/pktloc_grammar.l b/lib/route/pktloc_grammar.l
index cbb42b38..ab592d1b 100644
--- a/lib/route/pktloc_grammar.l
+++ b/lib/route/pktloc_grammar.l
@@ -4,7 +4,11 @@
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/pktloc.h>
+ #include <linux/tc_ematch/tc_em_cmp.h>
#include "pktloc_syntax.h"
+
+ int pktloc_get_column(yyscan_t);
+ void pktloc_set_column(int, yyscan_t);
%}
%option 8bit
diff --git a/lib/route/qdisc.c b/lib/route/qdisc.c
index b8b6fa53..7413cf7e 100644
--- a/lib/route/qdisc.c
+++ b/lib/route/qdisc.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/qdisc.c Queueing Disciplines
*
@@ -520,7 +521,7 @@ static void qdisc_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p)
{
struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc;
- nl_dump(p, "refcnt %u ", qdisc->q_info);
+ nl_dump(p, "refcnt %u", qdisc->q_info);
}
static struct rtnl_tc_type_ops qdisc_ops = {
diff --git a/lib/route/qdisc/cbq.c b/lib/route/qdisc/cbq.c
index 95f17618..118f893d 100644
--- a/lib/route/qdisc/cbq.c
+++ b/lib/route/qdisc/cbq.c
@@ -28,11 +28,11 @@
*/
static const struct trans_tbl ovl_strategies[] = {
- __ADD(TC_CBQ_OVL_CLASSIC,classic)
- __ADD(TC_CBQ_OVL_DELAY,delay)
- __ADD(TC_CBQ_OVL_LOWPRIO,lowprio)
- __ADD(TC_CBQ_OVL_DROP,drop)
- __ADD(TC_CBQ_OVL_RCLASSIC,rclassic)
+ __ADD(TC_CBQ_OVL_CLASSIC,classic),
+ __ADD(TC_CBQ_OVL_DELAY,delay),
+ __ADD(TC_CBQ_OVL_LOWPRIO,lowprio),
+ __ADD(TC_CBQ_OVL_DROP,drop),
+ __ADD(TC_CBQ_OVL_RCLASSIC,rclassic),
};
/**
diff --git a/lib/route/qdisc/hfsc.c b/lib/route/qdisc/hfsc.c
new file mode 100644
index 00000000..ddd12425
--- /dev/null
+++ b/lib/route/qdisc/hfsc.c
@@ -0,0 +1,351 @@
+/*
+ * lib/route/qdisc/hfsc.c HFSC Qdisc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2014 Cong Wang <xiyou.wangcong@gmail.com>
+ */
+
+/**
+ * @ingroup qdisc
+ * @ingroup class
+ * @defgroup qdisc_hfsc Hierarchical Fair Service Curve (HFSC)
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/class.h>
+#include <netlink/route/link.h>
+#include <netlink/route/qdisc/hfsc.h>
+
+/** @cond SKIP */
+#define SCH_HFSC_CLS_HAS_RSC 0x001
+#define SCH_HFSC_CLS_HAS_FSC 0x002
+#define SCH_HFSC_CLS_HAS_USC 0x004
+
+#define SCH_HFSC_QD_HAS_DEFCLS 0x01
+/** @endcond */
+
+static struct nla_policy hfsc_policy[TCA_HFSC_MAX + 1] = {
+ [TCA_HFSC_RSC] = { .minlen = sizeof(struct tc_service_curve) },
+ [TCA_HFSC_FSC] = { .minlen = sizeof(struct tc_service_curve) },
+ [TCA_HFSC_USC] = { .minlen = sizeof(struct tc_service_curve) },
+};
+
+static int hfsc_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct rtnl_hfsc_qdisc *hfsc = data;
+ struct tc_hfsc_qopt *opts;
+
+ opts = (struct tc_hfsc_qopt *) tc->tc_opts->d_data;
+ hfsc->qh_defcls = opts->defcls;
+ hfsc->qh_mask |= SCH_HFSC_QD_HAS_DEFCLS;
+ return 0;
+}
+
+static int hfsc_class_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct nlattr *tb[TCA_HFSC_MAX + 1];
+ struct rtnl_hfsc_class *hfsc = data;
+ int err;
+
+ if ((err = tca_parse(tb, TCA_HFSC_MAX, tc, hfsc_policy)) < 0)
+ return err;
+
+ if (tb[TCA_HFSC_RSC]) {
+ struct tc_service_curve tsc;
+
+ nla_memcpy(&tsc, tb[TCA_HFSC_RSC], sizeof(tsc));
+ hfsc->ch_rsc = tsc;
+ hfsc->ch_mask |= SCH_HFSC_CLS_HAS_RSC;
+ }
+
+ if (tb[TCA_HFSC_FSC]) {
+ struct tc_service_curve tsc;
+
+ nla_memcpy(&tsc, tb[TCA_HFSC_FSC], sizeof(tsc));
+ hfsc->ch_fsc = tsc;
+ hfsc->ch_mask |= SCH_HFSC_CLS_HAS_FSC;
+ }
+
+ if (tb[TCA_HFSC_USC]) {
+ struct tc_service_curve tsc;
+
+ nla_memcpy(&tsc, tb[TCA_HFSC_USC], sizeof(tsc));
+ hfsc->ch_usc = tsc;
+ hfsc->ch_mask |= SCH_HFSC_CLS_HAS_USC;
+ }
+
+ return 0;
+}
+
+static void hfsc_qdisc_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_hfsc_qdisc *hfsc = data;
+
+ if (!hfsc)
+ return;
+
+ if (hfsc->qh_mask & SCH_HFSC_QD_HAS_DEFCLS) {
+ char buf[64];
+ nl_dump(p, " default-class %s",
+ rtnl_tc_handle2str(hfsc->qh_defcls, buf, sizeof(buf)));
+ }
+}
+
+static void hfsc_dump_tsc(struct nl_dump_params *p, struct tc_service_curve *tsc)
+{
+ nl_dump(p, " m1 %u d %u m2 %u\n", tsc->m1, tsc->d, tsc->m2);
+}
+
+static void hfsc_class_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_hfsc_class *hfsc = data;
+
+ if (!hfsc)
+ return;
+ if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_RSC)
+ hfsc_dump_tsc(p, &hfsc->ch_rsc);
+ if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_FSC)
+ hfsc_dump_tsc(p, &hfsc->ch_fsc);
+ if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_USC)
+ hfsc_dump_tsc(p, &hfsc->ch_usc);
+}
+
+static void hfsc_class_dump_details(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ return;
+}
+
+static int hfsc_qdisc_msg_fill(struct rtnl_tc *tc, void *data,
+ struct nl_msg *msg)
+{
+ struct rtnl_hfsc_qdisc *hfsc = data;
+ struct tc_hfsc_qopt opts = {0};
+
+ if (!hfsc)
+ BUG();
+
+ opts.defcls = hfsc->qh_defcls;
+ return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
+}
+
+static int hfsc_class_msg_fill(struct rtnl_tc *tc, void *data,
+ struct nl_msg *msg)
+{
+ struct rtnl_hfsc_class *hfsc = data;
+ struct tc_service_curve tsc;
+
+ if (!hfsc)
+ BUG();
+
+ if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_RSC) {
+ tsc = hfsc->ch_rsc;
+ NLA_PUT(msg, TCA_HFSC_RSC, sizeof(tsc), &tsc);
+ }
+
+ if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_FSC) {
+ tsc = hfsc->ch_fsc;
+ NLA_PUT(msg, TCA_HFSC_FSC, sizeof(tsc), &tsc);
+ }
+
+ if (hfsc->ch_mask & SCH_HFSC_CLS_HAS_USC) {
+ tsc = hfsc->ch_usc;
+ NLA_PUT(msg, TCA_HFSC_USC, sizeof(tsc), &tsc);
+ }
+
+ return 0;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+static struct rtnl_tc_ops hfsc_qdisc_ops;
+static struct rtnl_tc_ops hfsc_class_ops;
+
+static struct rtnl_hfsc_qdisc *hfsc_qdisc_data(const struct rtnl_qdisc *qdisc, int *err)
+{
+ return rtnl_tc_data_check(TC_CAST(qdisc), &hfsc_qdisc_ops, err);
+}
+
+static struct rtnl_hfsc_class *hfsc_class_data(const struct rtnl_class *class, int *err)
+{
+ return rtnl_tc_data_check(TC_CAST(class), &hfsc_class_ops, err);
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+/**
+ * Return default class of HFSC qdisc
+ * @arg qdisc hfsc qdisc object
+ *
+ * Returns the classid of the class where all unclassified traffic
+ * goes to.
+ *
+ * @return classid or TC_H_UNSPEC if unspecified.
+ */
+uint32_t rtnl_qdisc_hfsc_get_defcls(const struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_hfsc_qdisc *hfsc;
+
+ if ((hfsc = hfsc_qdisc_data(qdisc, NULL)) &&
+ (hfsc->qh_mask & SCH_HFSC_QD_HAS_DEFCLS))
+ return hfsc->qh_defcls;
+
+ return TC_H_UNSPEC;
+}
+
+/**
+ * Set default class of the hfsc qdisc to the specified value
+ * @arg qdisc qdisc to change
+ * @arg defcls new default class
+ */
+int rtnl_qdisc_hfsc_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
+{
+ struct rtnl_hfsc_qdisc *hfsc;
+ int err;
+
+ if (!(hfsc = hfsc_qdisc_data(qdisc, &err)))
+ return err;
+
+ hfsc->qh_defcls = defcls;
+ hfsc->qh_mask |= SCH_HFSC_QD_HAS_DEFCLS;
+
+ return 0;
+}
+
+int rtnl_class_hfsc_get_rsc(const struct rtnl_class *class, struct tc_service_curve *tsc)
+{
+ struct rtnl_hfsc_class *hfsc;
+ int err = -NLE_OPNOTSUPP;
+
+ if ((hfsc = hfsc_class_data(class, &err)) &&
+ (hfsc->ch_mask & SCH_HFSC_CLS_HAS_RSC)) {
+ *tsc = hfsc->ch_rsc;
+ return 0;
+ }
+
+ return err;
+}
+
+int rtnl_class_hfsc_set_rsc(struct rtnl_class *class, const struct tc_service_curve *tsc)
+{
+ struct rtnl_hfsc_class *hfsc;
+ int err;
+
+ if (!(hfsc = hfsc_class_data(class, &err)))
+ return err;
+
+ hfsc->ch_rsc = *tsc;
+ hfsc->ch_mask |= SCH_HFSC_CLS_HAS_RSC;
+
+ return 0;
+}
+
+int rtnl_class_hfsc_get_fsc(const struct rtnl_class *class, struct tc_service_curve *tsc)
+{
+ struct rtnl_hfsc_class *hfsc;
+ int err = -NLE_OPNOTSUPP;
+
+ if ((hfsc = hfsc_class_data(class, &err)) &&
+ (hfsc->ch_mask & SCH_HFSC_CLS_HAS_FSC)) {
+ *tsc = hfsc->ch_fsc;
+ return 0;
+ }
+
+ return err;
+}
+
+int rtnl_class_hfsc_set_fsc(struct rtnl_class *class, const struct tc_service_curve *tsc)
+{
+ struct rtnl_hfsc_class *hfsc;
+ int err;
+
+ if (!(hfsc = hfsc_class_data(class, &err)))
+ return err;
+
+ hfsc->ch_fsc = *tsc;
+ hfsc->ch_mask |= SCH_HFSC_CLS_HAS_FSC;
+
+ return 0;
+}
+
+int rtnl_class_hfsc_get_usc(const struct rtnl_class *class, struct tc_service_curve *tsc)
+{
+ struct rtnl_hfsc_class *hfsc;
+ int err = -NLE_OPNOTSUPP;
+
+ if ((hfsc = hfsc_class_data(class, &err)) &&
+ (hfsc->ch_mask & SCH_HFSC_CLS_HAS_USC)) {
+ *tsc = hfsc->ch_usc;
+ return 0;
+ }
+
+ return err;
+}
+
+int rtnl_class_hfsc_set_usc(struct rtnl_class *class, const struct tc_service_curve *tsc)
+{
+ struct rtnl_hfsc_class *hfsc;
+ int err;
+
+ if (!(hfsc = hfsc_class_data(class, &err)))
+ return err;
+
+ hfsc->ch_usc = *tsc;
+ hfsc->ch_mask |= SCH_HFSC_CLS_HAS_USC;
+
+ return 0;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops hfsc_qdisc_ops = {
+ .to_kind = "hfsc",
+ .to_type = RTNL_TC_TYPE_QDISC,
+ .to_size = sizeof(struct rtnl_hfsc_qdisc),
+ .to_msg_parser = hfsc_qdisc_msg_parser,
+ .to_dump[NL_DUMP_LINE] = hfsc_qdisc_dump_line,
+ .to_msg_fill = hfsc_qdisc_msg_fill,
+};
+
+static struct rtnl_tc_ops hfsc_class_ops = {
+ .to_kind = "hfsc",
+ .to_type = RTNL_TC_TYPE_CLASS,
+ .to_size = sizeof(struct rtnl_hfsc_class),
+ .to_msg_parser = hfsc_class_msg_parser,
+ .to_dump = {
+ [NL_DUMP_LINE] = hfsc_class_dump_line,
+ [NL_DUMP_DETAILS] = hfsc_class_dump_details,
+ },
+ .to_msg_fill = hfsc_class_msg_fill,
+};
+
+static void __init hfsc_init(void)
+{
+ rtnl_tc_register(&hfsc_qdisc_ops);
+ rtnl_tc_register(&hfsc_class_ops);
+}
+
+static void __exit hfsc_exit(void)
+{
+ rtnl_tc_unregister(&hfsc_qdisc_ops);
+ rtnl_tc_unregister(&hfsc_class_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/htb.c b/lib/route/qdisc/htb.c
index 5a61a4ea..e426a149 100644
--- a/lib/route/qdisc/htb.c
+++ b/lib/route/qdisc/htb.c
@@ -45,6 +45,8 @@
static struct nla_policy htb_policy[TCA_HTB_MAX+1] = {
[TCA_HTB_INIT] = { .minlen = sizeof(struct tc_htb_glob) },
[TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) },
+ [TCA_HTB_RATE64] = { .minlen = sizeof(uint64_t) },
+ [TCA_HTB_CEIL64] = { .minlen = sizeof(uint64_t) },
};
static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
@@ -55,7 +57,7 @@ static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
return err;
-
+
if (tb[TCA_HTB_INIT]) {
struct tc_htb_glob opts;
@@ -78,7 +80,7 @@ static int htb_class_msg_parser(struct rtnl_tc *tc, void *data)
if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
return err;
-
+
if (tb[TCA_HTB_PARMS]) {
struct tc_htb_opt opts;
@@ -86,10 +88,16 @@ static int htb_class_msg_parser(struct rtnl_tc *tc, void *data)
htb->ch_prio = opts.prio;
rtnl_copy_ratespec(&htb->ch_rate, &opts.rate);
rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil);
- htb->ch_rbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
- opts.rate.rate);
- htb->ch_cbuffer = rtnl_tc_calc_bufsize(nl_ticks2us(opts.cbuffer),
- opts.ceil.rate);
+
+ if (tb[TCA_HTB_RATE64])
+ nla_memcpy(&htb->ch_rate.rs_rate64, tb[TCA_HTB_RATE64], sizeof(uint64_t));
+ if (tb[TCA_HTB_CEIL64])
+ nla_memcpy(&htb->ch_ceil.rs_rate64, tb[TCA_HTB_CEIL64], sizeof(uint64_t));
+
+ htb->ch_rbuffer = rtnl_tc_calc_bufsize64(nl_ticks2us(opts.buffer),
+ htb->ch_rate.rs_rate64);
+ htb->ch_cbuffer = rtnl_tc_calc_bufsize64(nl_ticks2us(opts.cbuffer),
+ htb->ch_ceil.rs_rate64);
htb->ch_quantum = opts.quantum;
htb->ch_level = opts.level;
@@ -135,8 +143,8 @@ static void htb_class_dump_line(struct rtnl_tc *tc, void *data,
double r, rbit;
char *ru, *rubit;
- r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru);
- rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit);
+ r = nl_cancel_down_bytes(htb->ch_rate.rs_rate64, &ru);
+ rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate64*8, &rubit);
nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u",
r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log);
@@ -156,8 +164,8 @@ static void htb_class_dump_details(struct rtnl_tc *tc, void *data,
double r, rbit;
char *ru, *rubit;
- r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru);
- rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit);
+ r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate64, &ru);
+ rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate64*8, &rubit);
nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u",
r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log);
@@ -191,9 +199,9 @@ static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data,
{
struct rtnl_htb_qdisc *htb = data;
struct tc_htb_glob opts = {
- .version = TC_HTB_PROTOVER,
- .rate2quantum = 10,
- };
+ .version = TC_HTB_PROTOVER,
+ .rate2quantum = 10,
+ };
if (htb) {
if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
@@ -213,6 +221,8 @@ static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE];
struct tc_htb_opt opts;
int buffer, cbuffer;
+ uint64_t rate64;
+ uint64_t ceil64;
if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE))
BUG();
@@ -227,36 +237,43 @@ static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable);
rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate);
+ rate64 = htb->ch_rate.rs_rate64;
if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
rtnl_tc_build_rate_table(tc, &htb->ch_ceil, ctable);
rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil);
+ ceil64 = htb->ch_ceil.rs_rate64;
} else {
/*
* If not set, configured rate is used as ceil, which implies
* no borrowing.
*/
memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec));
+ ceil64 = rate64;
}
if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
buffer = htb->ch_rbuffer;
else
- buffer = opts.rate.rate / nl_get_psched_hz() + mtu; /* XXX */
+ buffer = rate64 / nl_get_psched_hz() + mtu; /* XXX */
- opts.buffer = nl_us2ticks(rtnl_tc_calc_txtime(buffer, opts.rate.rate));
+ opts.buffer = nl_us2ticks(rtnl_tc_calc_txtime64(buffer, rate64));
if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
cbuffer = htb->ch_cbuffer;
else
- cbuffer = opts.ceil.rate / nl_get_psched_hz() + mtu; /* XXX */
+ cbuffer = ceil64 / nl_get_psched_hz() + mtu; /* XXX */
- opts.cbuffer = nl_us2ticks(rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate));
+ opts.cbuffer = nl_us2ticks(rtnl_tc_calc_txtime64(cbuffer, ceil64));
if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
opts.quantum = htb->ch_quantum;
NLA_PUT(msg, TCA_HTB_PARMS, sizeof(opts), &opts);
+ if (rate64 > 0xFFFFFFFFull)
+ NLA_PUT(msg, TCA_HTB_RATE64, sizeof(uint64_t), &rate64);
+ if (ceil64 > 0xFFFFFFFFull)
+ NLA_PUT(msg, TCA_HTB_CEIL64, sizeof(uint64_t), &ceil64);
NLA_PUT(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable);
NLA_PUT(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable);
@@ -269,14 +286,14 @@ nla_put_failure:
static struct rtnl_tc_ops htb_qdisc_ops;
static struct rtnl_tc_ops htb_class_ops;
-static struct rtnl_htb_qdisc *htb_qdisc_data(struct rtnl_qdisc *qdisc)
+static struct rtnl_htb_qdisc *htb_qdisc_data(struct rtnl_qdisc *qdisc, int *err)
{
- return rtnl_tc_data_check(TC_CAST(qdisc), &htb_qdisc_ops);
+ return rtnl_tc_data_check(TC_CAST(qdisc), &htb_qdisc_ops, err);
}
-static struct rtnl_htb_class *htb_class_data(struct rtnl_class *class)
+static struct rtnl_htb_class *htb_class_data(struct rtnl_class *class, int *err)
{
- return rtnl_tc_data_check(TC_CAST(class), &htb_class_ops);
+ return rtnl_tc_data_check(TC_CAST(class), &htb_class_ops, err);
}
/**
@@ -294,8 +311,8 @@ uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc)
{
struct rtnl_htb_qdisc *htb;
- if ((htb = htb_qdisc_data(qdisc)) &&
- htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
+ if ((htb = htb_qdisc_data(qdisc, NULL)) &&
+ (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM))
return htb->qh_rate2quantum;
return 0;
@@ -304,9 +321,10 @@ uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc)
int rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum)
{
struct rtnl_htb_qdisc *htb;
+ int err;
- if (!(htb = htb_qdisc_data(qdisc)))
- return -NLE_OPNOTSUPP;
+ if (!(htb = htb_qdisc_data(qdisc, &err)))
+ return err;
htb->qh_rate2quantum = rate2quantum;
htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM;
@@ -327,7 +345,7 @@ uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc)
{
struct rtnl_htb_qdisc *htb;
- if ((htb = htb_qdisc_data(qdisc)) &&
+ if ((htb = htb_qdisc_data(qdisc, NULL)) &&
htb->qh_mask & SCH_HTB_HAS_DEFCLS)
return htb->qh_defcls;
@@ -342,9 +360,10 @@ uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc)
int rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
{
struct rtnl_htb_qdisc *htb;
+ int err;
- if (!(htb = htb_qdisc_data(qdisc)))
- return -NLE_OPNOTSUPP;
+ if (!(htb = htb_qdisc_data(qdisc, &err)))
+ return err;
htb->qh_defcls = defcls;
htb->qh_mask |= SCH_HTB_HAS_DEFCLS;
@@ -356,7 +375,8 @@ uint32_t rtnl_htb_get_prio(struct rtnl_class *class)
{
struct rtnl_htb_class *htb;
- if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_PRIO)
+ if ((htb = htb_class_data(class, NULL)) &&
+ (htb->ch_mask & SCH_HTB_HAS_PRIO))
return htb->ch_prio;
return 0;
@@ -365,9 +385,10 @@ uint32_t rtnl_htb_get_prio(struct rtnl_class *class)
int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio)
{
struct rtnl_htb_class *htb;
+ int err;
- if (!(htb = htb_class_data(class)))
- return -NLE_OPNOTSUPP;
+ if (!(htb = htb_class_data(class, &err)))
+ return err;
htb->ch_prio = prio;
htb->ch_mask |= SCH_HTB_HAS_PRIO;
@@ -379,15 +400,41 @@ int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio)
* Return rate of HTB class
* @arg class htb class object
*
- * @return Rate in bytes/s or 0 if unspecified.
+ * @return Rate in bytes/s or 0 if unspecified. If the value
+ * cannot be represented as 32 bit integer, (1<<32) is returned.
+ * Use rtnl_htb_get_rate64() instead.
*/
uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
{
struct rtnl_htb_class *htb;
- if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_RATE)
- return htb->ch_rate.rs_rate;
+ if ( !(htb = htb_class_data(class, NULL))
+ || !(htb->ch_mask & SCH_HTB_HAS_RATE))
+ return 0;
+
+ if (htb->ch_rate.rs_rate64 > 0xFFFFFFFFull)
+ return 0xFFFFFFFFull;
+
+ return htb->ch_rate.rs_rate64;
+}
+
+/**
+ * Return rate of HTB class
+ * @arg class htb class object
+ * @arg out_rate64 on success, the set rate.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_get_rate64(struct rtnl_class *class, uint64_t *out_rate64)
+{
+ struct rtnl_htb_class *htb;
+
+ if (!(htb = htb_class_data(class, NULL)))
+ return -NLE_INVAL;
+ if (!(htb->ch_mask & SCH_HTB_HAS_RATE))
+ return -NLE_NOATTR;
+ *out_rate64 = htb->ch_rate.rs_rate64;
return 0;
}
@@ -400,13 +447,26 @@ uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
*/
int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
{
+ return rtnl_htb_set_rate64(class, rate);
+}
+
+/**
+ * Set rate of HTB class
+ * @arg class htb class object
+ * @arg rate new rate in bytes per second
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_rate64(struct rtnl_class *class, uint64_t rate)
+{
struct rtnl_htb_class *htb;
+ int err;
- if (!(htb = htb_class_data(class)))
- return -NLE_OPNOTSUPP;
+ if (!(htb = htb_class_data(class, &err)))
+ return err;
htb->ch_rate.rs_cell_log = UINT8_MAX; /* use default value */
- htb->ch_rate.rs_rate = rate;
+ htb->ch_rate.rs_rate64 = rate;
htb->ch_mask |= SCH_HTB_HAS_RATE;
return 0;
@@ -416,15 +476,41 @@ int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
* Return ceil rate of HTB class
* @arg class htb class object
*
- * @return Ceil rate in bytes/s or 0 if unspecified
+ * @return Ceil rate in bytes/s or 0 if unspecified. If the value
+ * cannot be represented as 32 bit integer, (1<<32) is returned.
+ * Use rtnl_htb_get_ceil64() instead.
*/
uint32_t rtnl_htb_get_ceil(struct rtnl_class *class)
{
struct rtnl_htb_class *htb;
- if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_CEIL)
- return htb->ch_ceil.rs_rate;
+ if ( !(htb = htb_class_data(class, NULL))
+ || !(htb->ch_mask & SCH_HTB_HAS_CEIL))
+ return 0;
+
+ if (htb->ch_ceil.rs_rate64 > 0xFFFFFFFFull)
+ return 0xFFFFFFFFull;
+ return htb->ch_ceil.rs_rate64;
+}
+
+/**
+ * Return ceil rate of HTB class
+ * @arg class htb class object
+ * @arg out_ceil64 on success, the set ceil value.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_get_ceil64(struct rtnl_class *class, uint64_t *out_ceil64)
+{
+ struct rtnl_htb_class *htb;
+
+ if (!(htb = htb_class_data(class, NULL)))
+ return -NLE_INVAL;
+ if (!(htb->ch_mask & SCH_HTB_HAS_CEIL))
+ return -NLE_NOATTR;
+
+ *out_ceil64 = htb->ch_ceil.rs_rate64;
return 0;
}
@@ -437,13 +523,26 @@ uint32_t rtnl_htb_get_ceil(struct rtnl_class *class)
*/
int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
{
+ return rtnl_htb_set_ceil64(class, ceil);
+}
+
+/**
+ * Set ceil rate of HTB class
+ * @arg class htb class object
+ * @arg ceil64 new ceil rate number of bytes per second
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_htb_set_ceil64(struct rtnl_class *class, uint64_t ceil64)
+{
struct rtnl_htb_class *htb;
+ int err;
- if (!(htb = htb_class_data(class)))
- return -NLE_OPNOTSUPP;
+ if (!(htb = htb_class_data(class, &err)))
+ return err;
htb->ch_ceil.rs_cell_log = UINT8_MAX; /* use default value */
- htb->ch_ceil.rs_rate = ceil;
+ htb->ch_ceil.rs_rate64 = ceil64;
htb->ch_mask |= SCH_HTB_HAS_CEIL;
return 0;
@@ -459,7 +558,7 @@ uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class)
{
struct rtnl_htb_class *htb;
- if ((htb = htb_class_data(class)) &&
+ if ((htb = htb_class_data(class, NULL)) &&
htb->ch_mask & SCH_HTB_HAS_RBUFFER)
return htb->ch_rbuffer;
@@ -474,9 +573,10 @@ uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class)
int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer)
{
struct rtnl_htb_class *htb;
+ int err;
- if (!(htb = htb_class_data(class)))
- return -NLE_OPNOTSUPP;
+ if (!(htb = htb_class_data(class, &err)))
+ return err;
htb->ch_rbuffer = rbuffer;
htb->ch_mask |= SCH_HTB_HAS_RBUFFER;
@@ -494,7 +594,7 @@ uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *class)
{
struct rtnl_htb_class *htb;
- if ((htb = htb_class_data(class)) &&
+ if ((htb = htb_class_data(class, NULL)) &&
htb->ch_mask & SCH_HTB_HAS_CBUFFER)
return htb->ch_cbuffer;
@@ -509,9 +609,10 @@ uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *class)
int rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer)
{
struct rtnl_htb_class *htb;
+ int err;
- if (!(htb = htb_class_data(class)))
- return -NLE_OPNOTSUPP;
+ if (!(htb = htb_class_data(class, &err)))
+ return err;
htb->ch_cbuffer = cbuffer;
htb->ch_mask |= SCH_HTB_HAS_CBUFFER;
@@ -531,7 +632,7 @@ uint32_t rtnl_htb_get_quantum(struct rtnl_class *class)
{
struct rtnl_htb_class *htb;
- if ((htb = htb_class_data(class)) &&
+ if ((htb = htb_class_data(class, NULL)) &&
htb->ch_mask & SCH_HTB_HAS_QUANTUM)
return htb->ch_quantum;
@@ -550,9 +651,10 @@ uint32_t rtnl_htb_get_quantum(struct rtnl_class *class)
int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum)
{
struct rtnl_htb_class *htb;
+ int err;
- if (!(htb = htb_class_data(class)))
- return -NLE_OPNOTSUPP;
+ if (!(htb = htb_class_data(class, &err)))
+ return err;
htb->ch_quantum = quantum;
htb->ch_mask |= SCH_HTB_HAS_QUANTUM;
@@ -568,16 +670,18 @@ int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum)
* 0, root classes have level (TC_HTB_MAXDEPTH - 1). Interior classes
* have a level of one less than their parent.
*
- * @return Level or -NLE_OPNOTSUPP
+ * @return Level or a negative error code.
*/
int rtnl_htb_get_level(struct rtnl_class *class)
{
struct rtnl_htb_class *htb;
+ int err = -NLE_OPNOTSUPP;
- if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_LEVEL)
+ if ((htb = htb_class_data(class, &err)) &&
+ (htb->ch_mask & SCH_HTB_HAS_LEVEL))
return htb->ch_level;
- return -NLE_OPNOTSUPP;
+ return err;
}
/**
@@ -595,9 +699,10 @@ int rtnl_htb_get_level(struct rtnl_class *class)
int rtnl_htb_set_level(struct rtnl_class *class, int level)
{
struct rtnl_htb_class *htb;
+ int err;
- if (!(htb = htb_class_data(class)))
- return -NLE_OPNOTSUPP;
+ if (!(htb = htb_class_data(class, &err)))
+ return err;
htb->ch_level = level;
htb->ch_mask |= SCH_HTB_HAS_LEVEL;
diff --git a/lib/route/qdisc/mqprio.c b/lib/route/qdisc/mqprio.c
new file mode 100644
index 00000000..0d072476
--- /dev/null
+++ b/lib/route/qdisc/mqprio.c
@@ -0,0 +1,605 @@
+/*
+ * lib/route/qdisc/mqprio.c MQPRIO Qdisc/Class
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@westermo.se>
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/qdisc.h>
+#include <netlink/route/qdisc/mqprio.h>
+
+/** @cond SKIP */
+#define SCH_MQPRIO_ATTR_NUMTC (1 << 0)
+#define SCH_MQPRIO_ATTR_PRIOMAP (1 << 1)
+#define SCH_MQPRIO_ATTR_HW (1 << 2)
+#define SCH_MQPRIO_ATTR_QUEUE (1 << 3)
+#define SCH_MQPRIO_ATTR_MODE (1 << 4)
+#define SCH_MQPRIO_ATTR_SHAPER (1 << 5)
+#define SCH_MQPRIO_ATTR_MIN_RATE (1 << 6)
+#define SCH_MQPRIO_ATTR_MAX_RATE (1 << 7)
+/** @endcond */
+
+static struct nla_policy mqprio_policy[TCA_MQPRIO_MAX + 1] = {
+ [TCA_MQPRIO_MODE] = { .minlen = sizeof(uint16_t) },
+ [TCA_MQPRIO_SHAPER] = { .minlen = sizeof(uint16_t) },
+ [TCA_MQPRIO_MIN_RATE64] = { .type = NLA_NESTED },
+ [TCA_MQPRIO_MAX_RATE64] = { .type = NLA_NESTED },
+};
+
+static int mqprio_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct rtnl_mqprio *mqprio = data;
+ struct tc_mqprio_qopt *qopt;
+ struct nlattr *attr;
+ int len, rem, i, err;
+
+ if (tc->tc_opts->d_size < sizeof(*qopt))
+ return -NLE_INVAL;
+
+ qopt = (struct tc_mqprio_qopt *) tc->tc_opts->d_data;
+ mqprio->qm_num_tc = qopt->num_tc;
+ mqprio->qm_hw = qopt->hw;
+ memcpy(mqprio->qm_prio_map, qopt->prio_tc_map,
+ TC_QOPT_MAX_QUEUE * sizeof(uint8_t));
+ memcpy(mqprio->qm_count, qopt->count,
+ TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
+ memcpy(mqprio->qm_offset, qopt->offset,
+ TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
+ mqprio->qm_mask = (SCH_MQPRIO_ATTR_NUMTC | SCH_MQPRIO_ATTR_PRIOMAP |
+ SCH_MQPRIO_ATTR_QUEUE | SCH_MQPRIO_ATTR_HW);
+
+ len = tc->tc_opts->d_size - NLA_ALIGN(sizeof(*qopt));
+
+ if (len > 0) {
+ struct nlattr *tb[TCA_MQPRIO_MAX + 1];
+
+ err = nla_parse(tb, TCA_MQPRIO_MAX, (struct nlattr *)
+ ((char *) tc->tc_opts->d_data + NLA_ALIGN(sizeof(*qopt))),
+ len, mqprio_policy);
+ if (err < 0)
+ return err;
+
+ if (tb[TCA_MQPRIO_MODE]) {
+ mqprio->qm_mode = nla_get_u16(tb[TCA_MQPRIO_MODE]);
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_MODE;
+ }
+
+ if (tb[TCA_MQPRIO_SHAPER]) {
+ mqprio->qm_shaper = nla_get_u16(tb[TCA_MQPRIO_SHAPER]);
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_SHAPER;
+ }
+
+ if (tb[TCA_MQPRIO_MIN_RATE64]) {
+ i = 0;
+ nla_for_each_nested(attr, tb[TCA_MQPRIO_MIN_RATE64], rem) {
+ if (nla_type(attr) != TCA_MQPRIO_MIN_RATE64)
+ return -EINVAL;
+
+ if (i >= mqprio->qm_num_tc)
+ break;
+
+ mqprio->qm_min_rate[i] = nla_get_u64(attr);
+ }
+
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_MIN_RATE;
+ }
+
+ if (tb[TCA_MQPRIO_MAX_RATE64]) {
+ i = 0;
+ nla_for_each_nested(attr, tb[TCA_MQPRIO_MAX_RATE64], rem) {
+ if (nla_type(attr) != TCA_MQPRIO_MAX_RATE64)
+ return -EINVAL;
+
+ if (i >= mqprio->qm_num_tc)
+ break;
+
+ mqprio->qm_max_rate[i] = nla_get_u64(attr);
+ }
+
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_MAX_RATE;
+ }
+ }
+
+ return 0;
+}
+
+static int mqprio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct rtnl_mqprio *mqprio = data;
+ struct tc_mqprio_qopt qopt = { 0 };
+ struct nlattr *nest = NULL;
+ int i;
+
+ if (!mqprio ||
+ !(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC) ||
+ !(mqprio->qm_mask & SCH_MQPRIO_ATTR_PRIOMAP) ||
+ !(mqprio->qm_mask & SCH_MQPRIO_ATTR_QUEUE))
+ return -NLE_INVAL;
+
+ if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
+ qopt.hw = 0;
+ else
+ qopt.hw = mqprio->qm_hw;
+
+ qopt.num_tc = mqprio->qm_num_tc;
+ memcpy(qopt.count, mqprio->qm_count, TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
+ memcpy(qopt.offset, mqprio->qm_offset, TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
+ memcpy(qopt.prio_tc_map, mqprio->qm_prio_map, TC_QOPT_MAX_QUEUE * sizeof(uint8_t));
+
+ nlmsg_append(msg, &qopt, sizeof(qopt), NL_DONTPAD);
+
+ if (mqprio->qm_hw) {
+ if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MODE)
+ NLA_PUT_U16(msg, TCA_MQPRIO_MODE, mqprio->qm_mode);
+
+ if (mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER)
+ NLA_PUT_U16(msg, TCA_MQPRIO_SHAPER, mqprio->qm_shaper);
+
+ if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MIN_RATE) {
+ nest = nla_nest_start(msg, TCA_MQPRIO_MIN_RATE64);
+ if (!nest)
+ goto nla_put_failure;
+
+ for (i = 0; i < mqprio->qm_num_tc; i++) {
+ if (nla_put(msg, TCA_MQPRIO_MIN_RATE64,
+ sizeof(mqprio->qm_min_rate[i]),
+ &mqprio->qm_min_rate[i]) < 0)
+ goto nla_nest_cancel;
+ }
+ nla_nest_end(msg, nest);
+ }
+
+ if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MAX_RATE) {
+ nest = nla_nest_start(msg, TCA_MQPRIO_MAX_RATE64);
+ if (!nest)
+ goto nla_put_failure;
+
+ for (i = 0; i < mqprio->qm_num_tc; i++) {
+ if (nla_put(msg, TCA_MQPRIO_MAX_RATE64,
+ sizeof(mqprio->qm_max_rate[i]),
+ &mqprio->qm_max_rate[i]) < 0)
+ goto nla_nest_cancel;
+ }
+ nla_nest_end(msg, nest);
+ }
+ }
+
+ return 0;
+
+nla_nest_cancel:
+ nla_nest_cancel(msg, nest);
+ return -NLE_MSGSIZE;
+
+nla_put_failure:
+ return -NLE_MSGSIZE;
+}
+
+static void mqprio_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_mqprio *mqprio = data;
+
+ if (mqprio)
+ nl_dump(p, " num_tc %u", mqprio->qm_num_tc);
+}
+
+static void mqprio_dump_details(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_mqprio *mqprio = data;
+ int i;
+
+ if (!mqprio)
+ return;
+
+ nl_dump(p, "map [");
+
+ for (i = 0; i <= TC_QOPT_BITMASK; i++)
+ nl_dump(p, "%u%s", mqprio->qm_prio_map[i],
+ i < TC_QOPT_BITMASK ? " " : "");
+
+ nl_dump(p, "]\n");
+ nl_new_line(p);
+}
+
+/**
+ * @name Attribute Modification
+ * @{
+ */
+
+/**
+ * Set number of traffic classes.
+ * @arg qdisc MQPRIO qdisc to be modified.
+ * @arg num_tc Number of traffic classes to create.
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_mqprio_set_num_tc(struct rtnl_qdisc *qdisc, int num_tc)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ mqprio->qm_num_tc = num_tc;
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_NUMTC;
+ return 0;
+}
+
+/**
+ * Get number of traffic classes of MQPRIO qdisc.
+ * @arg qdisc MQPRIO qdisc.
+ * @return Number of traffic classes or a negative error code.
+ */
+int rtnl_qdisc_mqprio_get_num_tc(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
+ return -NLE_INVAL;
+
+ if (mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC)
+ return mqprio->qm_num_tc;
+ else
+ return -NLE_MISSING_ATTR;
+}
+
+/**
+ * Set priomap of the MQPRIO qdisc.
+ * @arg qdisc MQPRIO qdisc to be modified.
+ * @arg priomap New priority mapping.
+ * @arg len Length of priomap (# of elements).
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_mqprio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[],
+ int len)
+{
+ struct rtnl_mqprio *mqprio;
+ int i;
+
+ if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC))
+ return -NLE_MISSING_ATTR;
+
+ if ((len / sizeof(uint8_t)) > (TC_QOPT_BITMASK+1))
+ return -NLE_RANGE;
+
+ for (i = 0; i <= TC_QOPT_BITMASK; i++) {
+ if (priomap[i] > mqprio->qm_num_tc)
+ return -NLE_RANGE;
+ }
+
+ memcpy(mqprio->qm_prio_map, priomap, len * sizeof(uint8_t));
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_PRIOMAP;
+
+ return 0;
+}
+
+/**
+ * Get priomap of MQPRIO qdisc.
+ * @arg qdisc MQPRIO qdisc.
+ * @return Priority mapping as array of size TC_QOPT_BANDS+1
+ * or NULL if an error occured.
+ */
+uint8_t *rtnl_qdisc_mqprio_get_priomap(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
+ return NULL;
+
+ if (mqprio->qm_mask & SCH_MQPRIO_ATTR_PRIOMAP)
+ return mqprio->qm_prio_map;
+ else
+ return NULL;
+}
+
+/**
+ * Offload to HW or run in SW (default).
+ * @arg qdisc MQPRIO qdisc to be modified.
+ * @arg offload 1 - offload to HW, 0 - run in SW only (default).
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_mqprio_hw_offload(struct rtnl_qdisc *qdisc, int offload)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ switch (offload) {
+ case 0:
+ case 1:
+ mqprio->qm_hw = offload;
+ break;
+ default:
+ return -NLE_INVAL;
+ }
+
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_HW;
+ return 0;
+}
+
+/**
+ * Check whether running in HW or SW.
+ * @arg qdisc MQPRIO qdisc to be modified.
+ * @return 0 if running in SW, otherwise 1 (HW)
+ */
+int rtnl_qdisc_mqprio_get_hw_offload(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
+ return -NLE_INVAL;
+
+ if (mqprio->qm_mask & SCH_MQPRIO_ATTR_HW)
+ return mqprio->qm_hw;
+
+ return 0;
+}
+
+/**
+ * Set tc queue of the MQPRIO qdisc.
+ * @arg qdisc MQPRIO qdisc to be modified.
+ * @arg count count of queue range for each traffic class
+ * @arg offset offset of queue range for each traffic class
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_mqprio_set_queue(struct rtnl_qdisc *qdisc, uint16_t count[],
+ uint16_t offset[], int len)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_NUMTC))
+ return -NLE_MISSING_ATTR;
+
+ if ((len / sizeof(uint16_t)) > TC_QOPT_MAX_QUEUE)
+ return -NLE_RANGE;
+
+ memcpy(mqprio->qm_count, count, len * sizeof(uint16_t));
+ memcpy(mqprio->qm_offset, offset, len * sizeof(uint16_t));
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_QUEUE;
+
+ return 0;
+}
+
+/**
+ * Get tc queue of the MQPRIO qdisc.
+ * @arg qdisc MQPRIO qdisc to be modified.
+ * @arg count count of queue range for each traffic class
+ * @arg offset offset of queue range for each traffic class
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_mqprio_get_queue(struct rtnl_qdisc *qdisc, uint16_t *count,
+ uint16_t *offset)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
+ return -NLE_INVAL;
+
+ if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_QUEUE))
+ return -NLE_MISSING_ATTR;
+
+ memcpy(count, mqprio->qm_count, TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
+ memcpy(offset, mqprio->qm_offset, TC_QOPT_MAX_QUEUE * sizeof(uint16_t));
+
+ return 0;
+}
+
+/**
+ * Set mode of mqprio Qdisc
+ * @arg qdisc MQPRIO qdisc to be modified.
+ * @arg mode one of: TC_MQPRIO_MODE_DCB, TC_MQPRIO_MODE_CHANNEL
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_mqprio_set_mode(struct rtnl_qdisc *qdisc, uint16_t mode)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
+ return -NLE_MISSING_ATTR;
+
+ mqprio->qm_mode = mode;
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_MODE;
+
+ return 0;
+}
+
+/**
+ * Get mode of mqprio Qdisc
+ * @arg qdisc MQPRIO qdisc.
+ * @return mode on success or negative error code.
+ */
+int rtnl_qdisc_mqprio_get_mode(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
+ return -NLE_INVAL;
+
+ if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MODE)
+ return mqprio->qm_mode;
+ else
+ return -NLE_MISSING_ATTR;
+}
+
+/**
+ * Set shaper of mqprio Qdisc
+ * @arg qdisc MQPRIO qdisc to be modified.
+ * @arg shaper one of: TC_MQPRIO_SHAPER_DCB, TC_MQPRIO_SHAPER_BW_RATE
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_mqprio_set_shaper(struct rtnl_qdisc *qdisc, uint16_t shaper)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_HW))
+ return -NLE_MISSING_ATTR;
+
+ mqprio->qm_shaper = shaper;
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_SHAPER;
+
+ return 0;
+}
+
+/**
+ * Get shaper of mqprio Qdisc
+ * @arg qdisc MQPRIO qdisc.
+ * @return shaper on success or negative error code.
+ */
+int rtnl_qdisc_mqprio_get_shaper(struct rtnl_qdisc *qdisc)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
+ return -NLE_INVAL;
+
+ if (mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER)
+ return mqprio->qm_shaper;
+ else
+ return -NLE_MISSING_ATTR;
+}
+
+/**
+ * Set minimum value of bandwidth rate limit for each traffic class
+ * @arg qdisc MQPRIO qdisc.
+ * @arg min minimum rate for each traffic class
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_mqprio_set_min_rate(struct rtnl_qdisc *qdisc, uint64_t min[], int len)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER))
+ return -NLE_MISSING_ATTR;
+
+ if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
+ return -NLE_INVAL;
+
+ if ((len / sizeof(uint64_t)) > TC_QOPT_MAX_QUEUE)
+ return -NLE_RANGE;
+
+ memcpy(mqprio->qm_min_rate, min, len * sizeof(uint64_t));
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_MIN_RATE;
+
+ return 0;
+}
+
+/**
+ * Get minimum value of bandwidth rate limit for each traffic class
+ * @arg qdisc MQPRIO qdisc.
+ * @arg min minimum rate for each traffic class
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_mqprio_get_min_rate(struct rtnl_qdisc *qdisc, uint64_t *min)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
+ return -NLE_INVAL;
+
+ if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MIN_RATE) {
+ memcpy(min, mqprio->qm_min_rate, TC_QOPT_MAX_QUEUE * sizeof(uint64_t));
+ return 0;
+ }
+
+ return -NLE_MISSING_ATTR;
+}
+
+/**
+ * Set maximum value of bandwidth rate limit for each traffic class
+ * @arg qdisc MQPRIO qdisc.
+ * @arg max maximum rate for each traffic class
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_mqprio_set_max_rate(struct rtnl_qdisc *qdisc, uint64_t max[], int len)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data(TC_CAST(qdisc))))
+ return -NLE_NOMEM;
+
+ if (!(mqprio->qm_mask & SCH_MQPRIO_ATTR_SHAPER))
+ return -NLE_MISSING_ATTR;
+
+ if (mqprio->qm_shaper != TC_MQPRIO_SHAPER_BW_RATE)
+ return -NLE_INVAL;
+
+ if ((len / sizeof(uint64_t)) > TC_QOPT_MAX_QUEUE)
+ return -NLE_RANGE;
+
+ memcpy(mqprio->qm_max_rate, max, len * sizeof(uint64_t));
+ mqprio->qm_mask |= SCH_MQPRIO_ATTR_MAX_RATE;
+
+ return 0;
+}
+
+/**
+ * Get maximum value of bandwidth rate limit for each traffic class
+ * @arg qdisc MQPRIO qdisc.
+ * @arg min maximum rate for each traffic class
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_qdisc_mqprio_get_max_rate(struct rtnl_qdisc *qdisc, uint64_t *max)
+{
+ struct rtnl_mqprio *mqprio;
+
+ if (!(mqprio = rtnl_tc_data_peek(TC_CAST(qdisc))))
+ return -NLE_INVAL;
+
+ if (mqprio->qm_mask & SCH_MQPRIO_ATTR_MAX_RATE) {
+ memcpy(max, mqprio->qm_max_rate, TC_QOPT_MAX_QUEUE * sizeof(uint64_t));
+ return 0;
+ }
+
+ return -NLE_MISSING_ATTR;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops mqprio_ops = {
+ .to_kind = "mqprio",
+ .to_type = RTNL_TC_TYPE_QDISC,
+ .to_size = sizeof(struct rtnl_mqprio),
+ .to_msg_parser = mqprio_msg_parser,
+ .to_dump = {
+ [NL_DUMP_LINE] = mqprio_dump_line,
+ [NL_DUMP_DETAILS] = mqprio_dump_details,
+ },
+ .to_msg_fill = mqprio_msg_fill,
+};
+
+static void __init mqprio_init(void)
+{
+ rtnl_tc_register(&mqprio_ops);
+}
+
+static void __exit mqprio_exit(void)
+{
+ rtnl_tc_unregister(&mqprio_ops);
+}
+
+/** @} */
diff --git a/lib/route/qdisc/netem.c b/lib/route/qdisc/netem.c
index 06d9fe8c..17dee3b7 100644
--- a/lib/route/qdisc/netem.c
+++ b/lib/route/qdisc/netem.c
@@ -29,8 +29,8 @@
/** @cond SKIP */
#define SCH_NETEM_ATTR_LATENCY 0x0001
#define SCH_NETEM_ATTR_LIMIT 0x0002
-#define SCH_NETEM_ATTR_LOSS 0x0004
-#define SCH_NETEM_ATTR_GAP 0x0008
+#define SCH_NETEM_ATTR_LOSS 0x0004
+#define SCH_NETEM_ATTR_GAP 0x0008
#define SCH_NETEM_ATTR_DUPLICATE 0x0010
#define SCH_NETEM_ATTR_JITTER 0x0020
#define SCH_NETEM_ATTR_DELAY_CORR 0x0040
@@ -40,7 +40,7 @@
#define SCH_NETEM_ATTR_RO_CORR 0x0400
#define SCH_NETEM_ATTR_CORRUPT_PROB 0x0800
#define SCH_NETEM_ATTR_CORRUPT_CORR 0x1000
-#define SCH_NETEM_ATTR_DIST 0x2000
+#define SCH_NETEM_ATTR_DIST 0x2000
/** @endcond */
static struct nla_policy netem_policy[TCA_NETEM_MAX+1] = {
@@ -76,7 +76,7 @@ static int netem_msg_parser(struct rtnl_tc *tc, void *data)
struct nlattr *tb[TCA_NETEM_MAX+1];
err = nla_parse(tb, TCA_NETEM_MAX, (struct nlattr *)
- (tc->tc_opts->d_data + sizeof(*opts)),
+ ((char *) tc->tc_opts->d_data + sizeof(*opts)),
len, netem_policy);
if (err < 0) {
free(netem);
@@ -106,18 +106,18 @@ static int netem_msg_parser(struct rtnl_tc *tc, void *data)
netem->qnm_mask |= (SCH_NETEM_ATTR_RO_PROB |
SCH_NETEM_ATTR_RO_CORR);
}
-
+
if (tb[TCA_NETEM_CORRUPT]) {
struct tc_netem_corrupt corrupt;
-
+
nla_memcpy(&corrupt, tb[TCA_NETEM_CORRUPT], sizeof(corrupt));
netem->qnm_crpt.nmcr_probability = corrupt.probability;
netem->qnm_crpt.nmcr_correlation = corrupt.correlation;
-
+
netem->qnm_mask |= (SCH_NETEM_ATTR_CORRUPT_PROB |
SCH_NETEM_ATTR_CORRUPT_CORR);
}
-
+
/* sch_netem does not currently dump TCA_NETEM_DELAY_DIST */
netem->qnm_dist.dist_data = NULL;
netem->qnm_dist.dist_size = 0;
@@ -129,10 +129,10 @@ static int netem_msg_parser(struct rtnl_tc *tc, void *data)
static void netem_free_data(struct rtnl_tc *tc, void *data)
{
struct rtnl_netem *netem = data;
-
+
if (!netem)
return;
-
+
free(netem->qnm_dist.dist_data);
}
@@ -141,12 +141,69 @@ static void netem_dump_line(struct rtnl_tc *tc, void *data,
{
struct rtnl_netem *netem = data;
- if (netem)
- nl_dump(p, "limit %d", netem->qnm_limit);
+ if (netem) {
+ if (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT && netem->qnm_limit > 0)
+ nl_dump(p, " limit %dpkts", netem->qnm_limit);
+ else
+ nl_dump(p, " no limit");
+ }
+}
+
+static void netem_dump_details(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_netem *netem = data;
+ char buf[32];
+
+ if (netem) {
+ if (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY && netem->qnm_latency > 0) {
+ nl_msec2str(nl_ticks2us(netem->qnm_latency) / 1000, buf, sizeof(buf));
+ nl_dump(p, " latency %s", buf);
+
+ if (netem->qnm_mask & SCH_NETEM_ATTR_JITTER && netem->qnm_jitter > 0) {
+ nl_msec2str(nl_ticks2us(netem->qnm_jitter) / 1000, buf, sizeof(buf));
+ nl_dump(p, " jitter %s", buf);
+
+ if (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR && netem->qnm_corr.nmc_delay > 0)
+ nl_dump(p, " %d%", netem->qnm_corr.nmc_delay);
+ }
+ }
+
+ if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS && netem->qnm_loss > 0) {
+ nl_dump(p, " loss %d%", netem->qnm_loss);
+
+ if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR && netem->qnm_corr.nmc_loss > 0)
+ nl_dump(p, " %d%", netem->qnm_corr.nmc_loss);
+ }
+
+ if (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE && netem->qnm_duplicate > 0) {
+ nl_dump(p, " duplicate %d%", netem->qnm_duplicate);
+
+ if (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR && netem->qnm_corr.nmc_duplicate > 0)
+ nl_dump(p, " %d%", netem->qnm_corr.nmc_duplicate);
+ }
+
+ if (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB && netem->qnm_ro.nmro_probability > 0) {
+ nl_dump(p, " reorder %d%", netem->qnm_ro.nmro_probability);
+
+ if (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR && netem->qnm_ro.nmro_correlation > 0)
+ nl_dump(p, " %d%", netem->qnm_ro.nmro_correlation);
+
+ if (netem->qnm_mask & SCH_NETEM_ATTR_GAP && netem->qnm_gap > 0)
+ nl_dump(p, " gap %d", netem->qnm_gap);
+ }
+
+ if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB && netem->qnm_crpt.nmcr_probability > 0) {
+ nl_dump(p, " reorder %d%", netem->qnm_crpt.nmcr_probability);
+
+ if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR && netem->qnm_crpt.nmcr_correlation > 0)
+ nl_dump(p, " %d%", netem->qnm_crpt.nmcr_correlation);
+ }
+ }
}
static int netem_msg_fill_raw(struct rtnl_tc *tc, void *data,
- struct nl_msg *msg)
+ struct nl_msg *msg)
{
int err = 0;
struct tc_netem_qopt opts;
@@ -154,9 +211,13 @@ static int netem_msg_fill_raw(struct rtnl_tc *tc, void *data,
struct tc_netem_reorder reorder;
struct tc_netem_corrupt corrupt;
struct rtnl_netem *netem = data;
-
- unsigned char set_correlation = 0, set_reorder = 0,
- set_corrupt = 0, set_dist = 0;
+
+ unsigned char set_correlation = 0, set_reorder = 0;
+ unsigned char set_corrupt = 0, set_dist = 0;
+
+ struct nlattr* head;
+ struct nlattr* tail;
+ int old_len;
if (!netem)
BUG();
@@ -167,116 +228,111 @@ static int netem_msg_fill_raw(struct rtnl_tc *tc, void *data,
memset(&corrupt, 0, sizeof(corrupt));
msg->nm_nlh->nlmsg_flags |= NLM_F_REQUEST;
-
- if ( netem->qnm_ro.nmro_probability != 0 ) {
- if (netem->qnm_latency == 0) {
+
+ if (netem->qnm_ro.nmro_probability != 0) {
+ if (netem->qnm_latency == 0)
return -NLE_MISSING_ATTR;
- }
- if (netem->qnm_gap == 0) netem->qnm_gap = 1;
- }
- else if ( netem->qnm_gap ) {
+ if (netem->qnm_gap == 0)
+ netem->qnm_gap = 1;
+ } else if (netem->qnm_gap)
return -NLE_MISSING_ATTR;
- }
- if ( netem->qnm_corr.nmc_delay != 0 ) {
- if ( netem->qnm_latency == 0 || netem->qnm_jitter == 0) {
+ if (netem->qnm_corr.nmc_delay != 0) {
+ if (netem->qnm_latency == 0 || netem->qnm_jitter == 0)
return -NLE_MISSING_ATTR;
- }
set_correlation = 1;
}
-
- if ( netem->qnm_corr.nmc_loss != 0 ) {
- if ( netem->qnm_loss == 0 ) {
+
+ if (netem->qnm_corr.nmc_loss != 0) {
+ if (netem->qnm_loss == 0)
return -NLE_MISSING_ATTR;
- }
set_correlation = 1;
}
- if ( netem->qnm_corr.nmc_duplicate != 0 ) {
- if ( netem->qnm_duplicate == 0 ) {
+ if (netem->qnm_corr.nmc_duplicate != 0) {
+ if (netem->qnm_duplicate == 0)
return -NLE_MISSING_ATTR;
- }
set_correlation = 1;
}
-
- if ( netem->qnm_ro.nmro_probability != 0 ) set_reorder = 1;
- else if ( netem->qnm_ro.nmro_correlation != 0 ) {
- return -NLE_MISSING_ATTR;
- }
-
- if ( netem->qnm_crpt.nmcr_probability != 0 ) set_corrupt = 1;
- else if ( netem->qnm_crpt.nmcr_correlation != 0 ) {
- return -NLE_MISSING_ATTR;
- }
-
- if ( netem->qnm_dist.dist_data && netem->qnm_dist.dist_size ) {
- if (netem->qnm_latency == 0 || netem->qnm_jitter == 0) {
+
+ if (netem->qnm_ro.nmro_probability != 0)
+ set_reorder = 1;
+ else if (netem->qnm_ro.nmro_correlation != 0)
+ return -NLE_MISSING_ATTR;
+
+ if (netem->qnm_crpt.nmcr_probability != 0)
+ set_corrupt = 1;
+ else if (netem->qnm_crpt.nmcr_correlation != 0)
+ return -NLE_MISSING_ATTR;
+
+ if (netem->qnm_dist.dist_data && netem->qnm_dist.dist_size) {
+ if (netem->qnm_latency == 0 || netem->qnm_jitter == 0)
return -NLE_MISSING_ATTR;
- }
- else {
- /* Resize to accomodate the large distribution table */
- int new_msg_len = msg->nm_size + netem->qnm_dist.dist_size *
- sizeof(netem->qnm_dist.dist_data[0]);
-
- msg->nm_nlh = (struct nlmsghdr *) realloc(msg->nm_nlh, new_msg_len);
- if ( msg->nm_nlh == NULL )
- return -NLE_NOMEM;
- msg->nm_size = new_msg_len;
+ else {
+ /* Resize to accomodate the large distribution table */
+ int new_msg_len = msg->nm_size + netem->qnm_dist.dist_size *
+ sizeof(netem->qnm_dist.dist_data[0]);
+ struct nlmsghdr *new_nlh = realloc(msg->nm_nlh, new_msg_len);
+
+ if (new_nlh == NULL)
+ return -NLE_NOMEM;
+ msg->nm_nlh = new_nlh;
+ msg->nm_size = new_msg_len;
set_dist = 1;
}
}
-
+
opts.latency = netem->qnm_latency;
opts.limit = netem->qnm_limit ? netem->qnm_limit : 1000;
opts.loss = netem->qnm_loss;
opts.gap = netem->qnm_gap;
opts.duplicate = netem->qnm_duplicate;
opts.jitter = netem->qnm_jitter;
-
+
NLA_PUT(msg, TCA_OPTIONS, sizeof(opts), &opts);
-
- if ( set_correlation ) {
+
+ if (set_correlation) {
cor.delay_corr = netem->qnm_corr.nmc_delay;
cor.loss_corr = netem->qnm_corr.nmc_loss;
cor.dup_corr = netem->qnm_corr.nmc_duplicate;
NLA_PUT(msg, TCA_NETEM_CORR, sizeof(cor), &cor);
}
-
- if ( set_reorder ) {
+
+ if (set_reorder) {
reorder.probability = netem->qnm_ro.nmro_probability;
reorder.correlation = netem->qnm_ro.nmro_correlation;
NLA_PUT(msg, TCA_NETEM_REORDER, sizeof(reorder), &reorder);
}
-
- if ( set_corrupt ) {
+
+ if (set_corrupt) {
corrupt.probability = netem->qnm_crpt.nmcr_probability;
corrupt.correlation = netem->qnm_crpt.nmcr_correlation;
NLA_PUT(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt);
}
-
- if ( set_dist ) {
+
+ if (set_dist) {
NLA_PUT(msg, TCA_NETEM_DELAY_DIST,
- netem->qnm_dist.dist_size * sizeof(netem->qnm_dist.dist_data[0]),
- netem->qnm_dist.dist_data);
+ netem->qnm_dist.dist_size * sizeof(netem->qnm_dist.dist_data[0]),
+ netem->qnm_dist.dist_data);
}
/* Length specified in the TCA_OPTIONS section must span the entire
* remainder of the message. That's just the way that sch_netem expects it.
* Maybe there's a more succinct way to do this at a higher level.
*/
- struct nlattr* head = (struct nlattr *)(NLMSG_DATA(msg->nm_nlh) +
- NLMSG_LENGTH(sizeof(struct tcmsg)) - NLMSG_ALIGNTO);
-
- struct nlattr* tail = (struct nlattr *)(((void *) (msg->nm_nlh)) +
- NLMSG_ALIGN(msg->nm_nlh->nlmsg_len));
-
- int old_len = head->nla_len;
- head->nla_len = (void *)tail - (void *)head;
+ head = (struct nlattr *)(((char *) NLMSG_DATA(msg->nm_nlh)) +
+ NLMSG_LENGTH(sizeof(struct tcmsg)) - NLMSG_ALIGNTO);
+
+ tail = (struct nlattr *)(((char *) (msg->nm_nlh)) +
+ NLMSG_ALIGN(msg->nm_nlh->nlmsg_len));
+
+ old_len = head->nla_len;
+ head->nla_len = (char *)tail - (char *)head;
msg->nm_nlh->nlmsg_len += (head->nla_len - old_len);
-
+
return err;
nla_put_failure:
return -NLE_MSGSIZE;
@@ -299,7 +355,7 @@ void rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit)
if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
BUG();
-
+
netem->qnm_limit = limit;
netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT;
}
@@ -440,7 +496,7 @@ int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc)
* @name Corruption
* @{
*/
-
+
/**
* Set corruption probability of netem qdisc.
* @arg qdisc Netem qdisc to be modified.
@@ -815,17 +871,42 @@ int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_p
}
/**
- * Set the delay distribution. Latency/jitter must be set before applying.
+ * Set the delay distribution data. Latency/jitter must be set before applying.
* @arg qdisc Netem qdisc.
- * @arg dist_type The name of the distribution (type, file, path/file).
* @return 0 on success, error code on failure.
*/
-int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) {
+int rtnl_netem_set_delay_distribution_data(struct rtnl_qdisc *qdisc, const int16_t *data, size_t len) {
struct rtnl_netem *netem;
+ int16_t *new_data;
if (!(netem = rtnl_tc_data(TC_CAST(qdisc))))
BUG();
-
+
+ if (len > MAXDIST)
+ return -NLE_INVAL;
+
+ new_data = (int16_t *) calloc(len, sizeof(int16_t));
+ if (!new_data)
+ return -NLE_NOMEM;
+
+ free (netem->qnm_dist.dist_data);
+ netem->qnm_dist.dist_data = new_data;
+
+ memcpy(netem->qnm_dist.dist_data, data, len * sizeof(int16_t));
+
+ netem->qnm_dist.dist_size = len;
+ netem->qnm_mask |= SCH_NETEM_ATTR_DIST;
+
+ return 0;
+}
+
+/**
+ * Load the delay distribution from a file. Latency/jitter must be set before applying.
+ * @arg qdisc Netem qdisc.
+ * @arg dist_type The name of the distribution (type, file, path/file).
+ * @return 0 on success, error code on failure.
+ */
+int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) {
FILE *f;
int n = 0;
size_t i;
@@ -833,31 +914,39 @@ int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist
char *line;
char name[NAME_MAX];
char dist_suffix[] = ".dist";
-
+ int16_t *data;
+ char *test_suffix;
+
+ /* Check several locations for the dist file */
+ char *test_path[] = {
+ "",
+ "./",
+ "/usr/lib/tc/",
+ "/usr/lib64/tc/",
+ "/usr/local/lib/tc/",
+ };
+
/* If the given filename already ends in .dist, don't append it later */
- char *test_suffix = strstr(dist_type, dist_suffix);
+ test_suffix = strstr(dist_type, dist_suffix);
if (test_suffix != NULL && strlen(test_suffix) == 5)
strcpy(dist_suffix, "");
-
- /* Check several locations for the dist file */
- char *test_path[] = { "", "./", "/usr/lib/tc/", "/usr/local/lib/tc/" };
-
+
for (i = 0; i < ARRAY_SIZE(test_path); i++) {
snprintf(name, NAME_MAX, "%s%s%s", test_path[i], dist_type, dist_suffix);
- if ((f = fopen(name, "r")))
+ if ((f = fopen(name, "re")))
break;
}
-
- if ( f == NULL )
+
+ if (f == NULL)
return -nl_syserr2nlerr(errno);
-
- netem->qnm_dist.dist_data = (int16_t *) calloc (MAXDIST, sizeof(int16_t));
-
+
+ data = (int16_t *) calloc (MAXDIST, sizeof(int16_t));
+
line = (char *) calloc (sizeof(char), len + 1);
-
+
while (getline(&line, &len, f) != -1) {
char *p, *endp;
-
+
if (*line == '\n' || *line == '#')
continue;
@@ -870,17 +959,16 @@ int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist
fclose(f);
return -NLE_INVAL;
}
- netem->qnm_dist.dist_data[n++] = x;
- }
+ data[n++] = x;
+ }
}
-
+
free(line);
-
- netem->qnm_dist.dist_size = n;
- netem->qnm_mask |= SCH_NETEM_ATTR_DIST;
-
fclose(f);
- return 0;
+
+ i = rtnl_netem_set_delay_distribution_data(qdisc, data, n);
+ free(data);
+ return i;
}
/** @} */
@@ -892,6 +980,7 @@ static struct rtnl_tc_ops netem_ops = {
.to_msg_parser = netem_msg_parser,
.to_free_data = netem_free_data,
.to_dump[NL_DUMP_LINE] = netem_dump_line,
+ .to_dump[NL_DUMP_DETAILS] = netem_dump_details,
.to_msg_fill_raw = netem_msg_fill_raw,
};
diff --git a/lib/route/qdisc/prio.c b/lib/route/qdisc/prio.c
index 54a46f01..5a217294 100644
--- a/lib/route/qdisc/prio.c
+++ b/lib/route/qdisc/prio.c
@@ -215,12 +215,12 @@ uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc)
*/
static const struct trans_tbl prios[] = {
- __ADD(TC_PRIO_BESTEFFORT,besteffort)
- __ADD(TC_PRIO_FILLER,filler)
- __ADD(TC_PRIO_BULK,bulk)
- __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk)
- __ADD(TC_PRIO_INTERACTIVE,interactive)
- __ADD(TC_PRIO_CONTROL,control)
+ __ADD(TC_PRIO_BESTEFFORT,besteffort),
+ __ADD(TC_PRIO_FILLER,filler),
+ __ADD(TC_PRIO_BULK,bulk),
+ __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk),
+ __ADD(TC_PRIO_INTERACTIVE,interactive),
+ __ADD(TC_PRIO_CONTROL,control),
};
/**
diff --git a/lib/route/qdisc/tbf.c b/lib/route/qdisc/tbf.c
index eb574d95..23cc8454 100644
--- a/lib/route/qdisc/tbf.c
+++ b/lib/route/qdisc/tbf.c
@@ -44,24 +44,24 @@ static int tbf_msg_parser(struct rtnl_tc *tc, void *data)
if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0)
return err;
-
+
if (tb[TCA_TBF_PARMS]) {
struct tc_tbf_qopt opts;
int bufsize;
nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts));
tbf->qt_limit = opts.limit;
-
+
rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate);
tbf->qt_rate_txtime = opts.buffer;
- bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer),
- opts.rate.rate);
+ bufsize = rtnl_tc_calc_bufsize64(nl_ticks2us(opts.buffer),
+ tbf->qt_rate.rs_rate64);
tbf->qt_rate_bucket = bufsize;
rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate);
tbf->qt_peakrate_txtime = opts.mtu;
- bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu),
- opts.peakrate.rate);
+ bufsize = rtnl_tc_calc_bufsize64(nl_ticks2us(opts.mtu),
+ tbf->qt_peakrate.rs_rate64);
tbf->qt_peakrate_bucket = bufsize;
rtnl_tc_set_mpu(tc, tbf->qt_rate.rs_mpu);
@@ -83,8 +83,8 @@ static void tbf_dump_line(struct rtnl_tc *tc, void *data,
if (!tbf)
return;
- r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru);
- rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit);
+ r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate64, &ru);
+ rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate64*8, &rubit);
lim = nl_cancel_down_bytes(tbf->qt_limit, &limu);
nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s",
@@ -114,9 +114,9 @@ static void tbf_dump_details(struct rtnl_tc *tc, void *data,
if (tbf->qt_mask & TBF_ATTR_PEAKRATE) {
char *pru, *prbu, *bsu, *clu;
double pr, prb, bs, cl;
-
- pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru);
- prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu);
+
+ pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate64, &pru);
+ prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate64 * 8, &prbu);
bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu);
cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log,
&clu);
@@ -191,7 +191,7 @@ static inline double calc_limit(struct rtnl_ratespec *spec, int latency,
{
double limit;
- limit = (double) spec->rs_rate * ((double) latency / 1000000.);
+ limit = (double) spec->rs_rate64 * ((double) latency / 1000000.);
limit += bucket;
return limit;
@@ -278,7 +278,7 @@ void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
{
struct rtnl_tbf *tbf;
int cell_log;
-
+
if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
BUG();
@@ -287,10 +287,10 @@ void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket,
else
cell_log = rtnl_tc_calc_cell_log(cell);
- tbf->qt_rate.rs_rate = rate;
+ tbf->qt_rate.rs_rate64 = (uint32_t)rate;
tbf->qt_rate_bucket = bucket;
tbf->qt_rate.rs_cell_log = cell_log;
- tbf->qt_rate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate));
+ tbf->qt_rate_txtime = nl_us2ticks(rtnl_tc_calc_txtime64(bucket, tbf->qt_rate.rs_rate64));
tbf->qt_mask |= TBF_ATTR_RATE;
}
@@ -307,7 +307,7 @@ int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc)
BUG();
if (tbf->qt_mask & TBF_ATTR_RATE)
- return tbf->qt_rate.rs_rate;
+ return tbf->qt_rate.rs_rate64;
else
return -1;
}
@@ -361,7 +361,7 @@ int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
{
struct rtnl_tbf *tbf;
int cell_log;
-
+
if (!(tbf = rtnl_tc_data(TC_CAST(qdisc))))
BUG();
@@ -369,11 +369,11 @@ int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket,
if (cell_log < 0)
return cell_log;
- tbf->qt_peakrate.rs_rate = rate;
+ tbf->qt_peakrate.rs_rate64 = (uint32_t)rate;
tbf->qt_peakrate_bucket = bucket;
tbf->qt_peakrate.rs_cell_log = cell_log;
- tbf->qt_peakrate_txtime = nl_us2ticks(rtnl_tc_calc_txtime(bucket, rate));
-
+ tbf->qt_peakrate_txtime = nl_us2ticks(rtnl_tc_calc_txtime64(bucket, tbf->qt_peakrate.rs_rate64));
+
tbf->qt_mask |= TBF_ATTR_PEAKRATE;
return 0;
@@ -392,7 +392,7 @@ int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc)
BUG();
if (tbf->qt_mask & TBF_ATTR_PEAKRATE)
- return tbf->qt_peakrate.rs_rate;
+ return tbf->qt_peakrate.rs_rate64;
else
return -1;
}
diff --git a/lib/route/route.c b/lib/route/route.c
index 29851873..0900b774 100644
--- a/lib/route/route.c
+++ b/lib/route/route.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/route.c Routes
*
@@ -173,6 +174,7 @@ int rtnl_route_delete(struct nl_sock *sk, struct rtnl_route *route, int flags)
static struct nl_af_group route_groups[] = {
{ AF_INET, RTNLGRP_IPV4_ROUTE },
{ AF_INET6, RTNLGRP_IPV6_ROUTE },
+ { AF_MPLS, RTNLGRP_MPLS_ROUTE },
{ AF_DECnet, RTNLGRP_DECnet_ROUTE },
{ END_OF_GROUP_LIST },
};
diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c
index dd4bf49e..bacabe85 100644
--- a/lib/route/route_obj.c
+++ b/lib/route/route_obj.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/route_obj.c Route Object
*
@@ -31,6 +32,8 @@
*/
#include <netlink-private/netlink.h>
+#include <netlink-private/utils.h>
+#include <netlink-private/route/nexthop-encap.h>
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/utils.h>
@@ -40,6 +43,7 @@
#include <netlink/route/route.h>
#include <netlink/route/link.h>
#include <netlink/route/nexthop.h>
+#include <linux/in_route.h>
/** @cond SKIP */
#define ROUTE_ATTR_FAMILY 0x000001
@@ -60,6 +64,7 @@
#define ROUTE_ATTR_MULTIPATH 0x008000
#define ROUTE_ATTR_REALMS 0x010000
#define ROUTE_ATTR_CACHEINFO 0x020000
+#define ROUTE_ATTR_TTL_PROPAGATE 0x040000
/** @endcond */
static void route_constructor(struct nl_object *c)
@@ -243,6 +248,11 @@ static void route_dump_details(struct nl_object *a, struct nl_dump_params *p)
if (r->ce_mask & ROUTE_ATTR_SRC)
nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf)));
+ if (r->ce_mask & ROUTE_ATTR_TTL_PROPAGATE) {
+ nl_dump(p, " ttl-propagate %s",
+ r->rt_ttl_propagate ? "enabled" : "disabled");
+ }
+
nl_dump(p, "\n");
if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
@@ -259,7 +269,7 @@ static void route_dump_details(struct nl_object *a, struct nl_dump_params *p)
if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) {
nl_dump_line(p, " cacheinfo error %d (%s)\n",
r->rt_cacheinfo.rtci_error,
- strerror_r(-r->rt_cacheinfo.rtci_error, buf, sizeof(buf)));
+ nl_strerror_l(-r->rt_cacheinfo.rtci_error));
}
if (r->ce_mask & ROUTE_ATTR_METRICS) {
@@ -343,13 +353,27 @@ static void route_keygen(struct nl_object *obj, uint32_t *hashkey,
return;
}
-static int route_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint32_t route_id_attrs_get(struct nl_object *obj)
+{
+ struct rtnl_route *route = (struct rtnl_route *)obj;
+ struct nl_object_ops *ops = obj->ce_ops;
+ uint32_t rv = ops->oo_id_attrs;
+
+ /* MPLS address family does not allow RTA_PRIORITY to be set */
+ if (route->rt_family == AF_MPLS)
+ rv &= ~ROUTE_ATTR_PRIO;
+
+ return rv;
+}
+
+static uint64_t route_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct rtnl_route *a = (struct rtnl_route *) _a;
struct rtnl_route *b = (struct rtnl_route *) _b;
struct rtnl_nexthop *nh_a, *nh_b;
- int i, diff = 0, found;
+ int i, found;
+ uint64_t diff = 0;
#define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR)
@@ -365,6 +389,8 @@ static int route_compare(struct nl_object *_a, struct nl_object *_b,
diff |= ROUTE_DIFF(IIF, a->rt_iif != b->rt_iif);
diff |= ROUTE_DIFF(PREF_SRC, nl_addr_cmp(a->rt_pref_src,
b->rt_pref_src));
+ diff |= ROUTE_DIFF(TTL_PROPAGATE,
+ a->rt_ttl_propagate != b->rt_ttl_propagate);
if (flags & LOOSE_COMPARISON) {
nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
@@ -544,24 +570,25 @@ static int route_update(struct nl_object *old_obj, struct nl_object *new_obj)
}
static const struct trans_tbl route_attrs[] = {
- __ADD(ROUTE_ATTR_FAMILY, family)
- __ADD(ROUTE_ATTR_TOS, tos)
- __ADD(ROUTE_ATTR_TABLE, table)
- __ADD(ROUTE_ATTR_PROTOCOL, protocol)
- __ADD(ROUTE_ATTR_SCOPE, scope)
- __ADD(ROUTE_ATTR_TYPE, type)
- __ADD(ROUTE_ATTR_FLAGS, flags)
- __ADD(ROUTE_ATTR_DST, dst)
- __ADD(ROUTE_ATTR_SRC, src)
- __ADD(ROUTE_ATTR_IIF, iif)
- __ADD(ROUTE_ATTR_OIF, oif)
- __ADD(ROUTE_ATTR_GATEWAY, gateway)
- __ADD(ROUTE_ATTR_PRIO, prio)
- __ADD(ROUTE_ATTR_PREF_SRC, pref_src)
- __ADD(ROUTE_ATTR_METRICS, metrics)
- __ADD(ROUTE_ATTR_MULTIPATH, multipath)
- __ADD(ROUTE_ATTR_REALMS, realms)
- __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo)
+ __ADD(ROUTE_ATTR_FAMILY, family),
+ __ADD(ROUTE_ATTR_TOS, tos),
+ __ADD(ROUTE_ATTR_TABLE, table),
+ __ADD(ROUTE_ATTR_PROTOCOL, protocol),
+ __ADD(ROUTE_ATTR_SCOPE, scope),
+ __ADD(ROUTE_ATTR_TYPE, type),
+ __ADD(ROUTE_ATTR_FLAGS, flags),
+ __ADD(ROUTE_ATTR_DST, dst),
+ __ADD(ROUTE_ATTR_SRC, src),
+ __ADD(ROUTE_ATTR_IIF, iif),
+ __ADD(ROUTE_ATTR_OIF, oif),
+ __ADD(ROUTE_ATTR_GATEWAY, gateway),
+ __ADD(ROUTE_ATTR_PRIO, prio),
+ __ADD(ROUTE_ATTR_PREF_SRC, pref_src),
+ __ADD(ROUTE_ATTR_METRICS, metrics),
+ __ADD(ROUTE_ATTR_MULTIPATH, multipath),
+ __ADD(ROUTE_ATTR_REALMS, realms),
+ __ADD(ROUTE_ATTR_CACHEINFO, cacheinfo),
+ __ADD(ROUTE_ATTR_TTL_PROPAGATE, ttl_propagate),
};
static char *route_attrs2str(int attrs, char *buf, size_t len)
@@ -654,13 +681,17 @@ uint32_t rtnl_route_get_priority(struct rtnl_route *route)
int rtnl_route_set_family(struct rtnl_route *route, uint8_t family)
{
- if (family != AF_INET && family != AF_INET6 && family != AF_DECnet)
- return -NLE_AF_NOSUPPORT;
-
- route->rt_family = family;
- route->ce_mask |= ROUTE_ATTR_FAMILY;
+ switch(family) {
+ case AF_INET:
+ case AF_INET6:
+ case AF_DECnet:
+ case AF_MPLS:
+ route->rt_family = family;
+ route->ce_mask |= ROUTE_ATTR_FAMILY;
+ return 0;
+ }
- return 0;
+ return -NLE_AF_NOSUPPORT;
}
uint8_t rtnl_route_get_family(struct rtnl_route *route)
@@ -681,7 +712,7 @@ int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
nl_addr_get(addr);
route->rt_dst = addr;
-
+
route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY);
return 0;
@@ -867,10 +898,10 @@ void rtnl_route_foreach_nexthop(struct rtnl_route *r,
void *arg)
{
struct rtnl_nexthop *nh;
-
+
if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
- cb(nh, arg);
+ cb(nh, arg);
}
}
}
@@ -879,15 +910,30 @@ struct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n)
{
struct rtnl_nexthop *nh;
uint32_t i;
-
+
if (r->ce_mask & ROUTE_ATTR_MULTIPATH && r->rt_nr_nh > n) {
i = 0;
nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
- if (i == n) return nh;
+ if (i == n) return nh;
i++;
}
}
- return NULL;
+ return NULL;
+}
+
+void rtnl_route_set_ttl_propagate(struct rtnl_route *route, uint8_t ttl_prop)
+{
+ route->rt_ttl_propagate = ttl_prop;
+ route->ce_mask |= ROUTE_ATTR_TTL_PROPAGATE;
+}
+
+int rtnl_route_get_ttl_propagate(struct rtnl_route *route)
+{
+ if (!route)
+ return -NLE_INVAL;
+ if (!(route->ce_mask & ROUTE_ATTR_TTL_PROPAGATE))
+ return -NLE_MISSING_ATTR;
+ return route->rt_ttl_propagate;
}
/** @} */
@@ -915,6 +961,9 @@ int rtnl_route_guess_scope(struct rtnl_route *route)
if (route->rt_type == RTN_LOCAL)
return RT_SCOPE_HOST;
+ if (route->rt_family == AF_MPLS)
+ return RT_SCOPE_UNIVERSE;
+
if (!nl_list_empty(&route->rt_nexthops)) {
struct rtnl_nexthop *nh;
@@ -933,6 +982,31 @@ int rtnl_route_guess_scope(struct rtnl_route *route)
/** @} */
+static struct nl_addr *rtnl_route_parse_via(struct nlattr *nla)
+{
+ int alen = nla_len(nla) - offsetof(struct rtvia, rtvia_addr);
+ struct rtvia *via = nla_data(nla);
+
+ return nl_addr_build(via->rtvia_family, via->rtvia_addr, alen);
+}
+
+static int rtnl_route_put_via(struct nl_msg *msg, struct nl_addr *addr)
+{
+ unsigned int alen = nl_addr_get_len(addr);
+ struct nlattr *nla;
+ struct rtvia *via;
+
+ nla = nla_reserve(msg, RTA_VIA, alen + sizeof(*via));
+ if (!nla)
+ return -EMSGSIZE;
+
+ via = nla_data(nla);
+ via->rtvia_family = nl_addr_get_family(addr);
+ memcpy(via->rtvia_addr, nl_addr_get_binary_addr(addr), alen);
+
+ return 0;
+}
+
static struct nla_policy route_policy[RTA_MAX+1] = {
[RTA_IIF] = { .type = NLA_U32 },
[RTA_OIF] = { .type = NLA_U32 },
@@ -941,6 +1015,9 @@ static struct nla_policy route_policy[RTA_MAX+1] = {
[RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
[RTA_METRICS] = { .type = NLA_NESTED },
[RTA_MULTIPATH] = { .type = NLA_NESTED },
+ [RTA_TTL_PROPAGATE] = { .type = NLA_U8 },
+ [RTA_ENCAP] = { .type = NLA_NESTED },
+ [RTA_ENCAP_TYPE] = { .type = NLA_U16 },
};
static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
@@ -985,10 +1062,45 @@ static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
if (ntb[RTA_FLOW]) {
uint32_t realms;
-
+
realms = nla_get_u32(ntb[RTA_FLOW]);
rtnl_route_nh_set_realms(nh, realms);
}
+
+ if (ntb[RTA_NEWDST]) {
+ struct nl_addr *addr;
+
+ addr = nl_addr_alloc_attr(ntb[RTA_NEWDST],
+ route->rt_family);
+ if (!addr)
+ goto errout;
+
+ err = rtnl_route_nh_set_newdst(nh, addr);
+ nl_addr_put(addr);
+ if (err)
+ goto errout;
+ }
+
+ if (ntb[RTA_VIA]) {
+ struct nl_addr *addr;
+
+ addr = rtnl_route_parse_via(ntb[RTA_VIA]);
+ if (!addr)
+ goto errout;
+
+ err = rtnl_route_nh_set_via(nh, addr);
+ nl_addr_put(addr);
+ if (err)
+ goto errout;
+ }
+
+ if (ntb[RTA_ENCAP] && ntb[RTA_ENCAP_TYPE]) {
+ err = nh_encap_parse_msg(ntb[RTA_ENCAP],
+ ntb[RTA_ENCAP_TYPE],
+ nh);
+ if (err)
+ goto errout;
+ }
}
rtnl_route_add_nexthop(route, nh);
@@ -1014,10 +1126,8 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
int err, family;
route = rtnl_route_alloc();
- if (!route) {
- err = -NLE_NOMEM;
- goto errout;
- }
+ if (!route)
+ goto errout_nomem;
route->ce_msgtype = nlh->nlmsg_type;
@@ -1038,7 +1148,13 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE |
ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL |
- ROUTE_ATTR_FLAGS | ROUTE_ATTR_PRIO;
+ ROUTE_ATTR_FLAGS;
+
+ /* right now MPLS does not allow rt_prio to be set, so don't
+ * assume it is unless it comes from an attribute
+ */
+ if (family != AF_MPLS)
+ route->ce_mask |= ROUTE_ATTR_PRIO;
if (tb[RTA_DST]) {
if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
@@ -1096,7 +1212,9 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
for (i = 1; i <= RTAX_MAX; i++) {
if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
uint32_t m = nla_get_u32(mtb[i]);
- if (rtnl_route_set_metric(route, i, m) < 0)
+
+ err = rtnl_route_set_metric(route, i, m);
+ if (err < 0)
goto errout;
}
}
@@ -1114,14 +1232,14 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
if (tb[RTA_OIF]) {
if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
- goto errout;
+ goto errout_nomem;
rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF]));
}
if (tb[RTA_GATEWAY]) {
if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
- goto errout;
+ goto errout_nomem;
if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family)))
goto errout_nomem;
@@ -1132,11 +1250,59 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
if (tb[RTA_FLOW]) {
if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
- goto errout;
+ goto errout_nomem;
rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW]));
}
+ if (tb[RTA_NEWDST]) {
+ struct nl_addr *addr;
+
+ if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+ goto errout_nomem;
+
+ addr = nl_addr_alloc_attr(tb[RTA_NEWDST], route->rt_family);
+ if (!addr)
+ goto errout_nomem;
+
+ err = rtnl_route_nh_set_newdst(old_nh, addr);
+ nl_addr_put(addr);
+ if (err)
+ goto errout;
+ }
+
+ if (tb[RTA_VIA]) {
+ int alen = nla_len(tb[RTA_VIA]) - offsetof(struct rtvia, rtvia_addr);
+ struct rtvia *via = nla_data(tb[RTA_VIA]);
+
+ if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+ goto errout_nomem;
+
+ addr = nl_addr_build(via->rtvia_family, via->rtvia_addr, alen);
+ if (!addr)
+ goto errout_nomem;
+
+ err = rtnl_route_nh_set_via(old_nh, addr);
+ nl_addr_put(addr);
+ if (err)
+ goto errout;
+ }
+
+ if (tb[RTA_TTL_PROPAGATE]) {
+ rtnl_route_set_ttl_propagate(route,
+ nla_get_u8(tb[RTA_TTL_PROPAGATE]));
+ }
+
+ if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]) {
+ if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+ goto errout_nomem;
+
+ err = nh_encap_parse_msg(tb[RTA_ENCAP],
+ tb[RTA_ENCAP_TYPE], old_nh);
+ if (err)
+ goto errout;
+ }
+
if (old_nh) {
rtnl_route_nh_set_flags(old_nh, rtm->rtm_flags & 0xff);
if (route->rt_nr_nh == 0) {
@@ -1163,12 +1329,15 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
rtnl_route_nh_free(old_nh);
}
+ old_nh = NULL;
}
*result = route;
return 0;
errout:
+ if (old_nh)
+ rtnl_route_nh_free(old_nh);
rtnl_route_put(route);
return err;
@@ -1211,12 +1380,17 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
goto nla_put_failure;
/* Additional table attribute replacing the 8bit in the header, was
- * required to allow more than 256 tables. */
- NLA_PUT_U32(msg, RTA_TABLE, route->rt_table);
+ * required to allow more than 256 tables. MPLS does not allow the
+ * table attribute to be set
+ */
+ if (route->rt_family != AF_MPLS)
+ NLA_PUT_U32(msg, RTA_TABLE, route->rt_table);
if (nl_addr_get_len(route->rt_dst))
NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst);
- NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio);
+
+ if (route->ce_mask & ROUTE_ATTR_PRIO)
+ NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio);
if (route->ce_mask & ROUTE_ATTR_SRC)
NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src);
@@ -1227,6 +1401,9 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
if (route->ce_mask & ROUTE_ATTR_IIF)
NLA_PUT_U32(msg, RTA_IIF, route->rt_iif);
+ if (route->ce_mask & ROUTE_ATTR_TTL_PROPAGATE)
+ NLA_PUT_U8(msg, RTA_TTL_PROPAGATE, route->rt_ttl_propagate);
+
if (route->rt_nmetrics > 0) {
uint32_t val;
@@ -1252,6 +1429,13 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
NLA_PUT_U32(msg, RTA_OIF, nh->rtnh_ifindex);
if (nh->rtnh_realms)
NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
+ if (nh->rtnh_newdst)
+ NLA_PUT_ADDR(msg, RTA_NEWDST, nh->rtnh_newdst);
+ if (nh->rtnh_via && rtnl_route_put_via(msg, nh->rtnh_via) < 0)
+ goto nla_put_failure;
+ if (nh->rtnh_encap &&
+ nh_encap_build_msg(msg, nh->rtnh_encap) < 0)
+ goto nla_put_failure;
} else if (rtnl_route_get_nnexthops(route) > 1) {
struct nlattr *multipath;
struct rtnl_nexthop *nh;
@@ -1274,11 +1458,22 @@ int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
NLA_PUT_ADDR(msg, RTA_GATEWAY,
nh->rtnh_gateway);
+ if (nh->rtnh_newdst)
+ NLA_PUT_ADDR(msg, RTA_NEWDST, nh->rtnh_newdst);
+
+ if (nh->rtnh_via &&
+ rtnl_route_put_via(msg, nh->rtnh_via) < 0)
+ goto nla_put_failure;
+
if (nh->rtnh_realms)
NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
- rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) -
- (void *) rtnh;
+ if (nh->rtnh_encap &&
+ nh_encap_build_msg(msg, nh->rtnh_encap) < 0)
+ goto nla_put_failure;
+
+ rtnh->rtnh_len = (char *) nlmsg_tail(msg->nm_nlh) -
+ (char *) rtnh;
}
nla_nest_end(msg, multipath);
@@ -1309,6 +1504,7 @@ struct nl_object_ops route_obj_ops = {
.oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
ROUTE_ATTR_TABLE | ROUTE_ATTR_DST |
ROUTE_ATTR_PRIO),
+ .oo_id_attrs_get = route_id_attrs_get,
};
/** @endcond */
diff --git a/lib/route/route_utils.c b/lib/route/route_utils.c
index a5b39661..6337f72a 100644
--- a/lib/route/route_utils.c
+++ b/lib/route/route_utils.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/route_utils.c Routing Utilities
*
@@ -62,7 +63,7 @@ static void __init init_routing_table_names(void)
add_routing_table_name(RT_TABLE_DEFAULT, "default");
add_routing_table_name(RT_TABLE_MAIN, "main");
add_routing_table_name(RT_TABLE_LOCAL, "local");
-};
+}
static void __exit release_routing_table_names(void)
{
@@ -108,7 +109,7 @@ static void __init init_proto_names(void)
add_proto_name(RTPROT_KERNEL, "kernel");
add_proto_name(RTPROT_BOOT, "boot");
add_proto_name(RTPROT_STATIC, "static");
-};
+}
static void __exit release_proto_names(void)
{
@@ -140,19 +141,19 @@ int rtnl_route_str2proto(const char *name)
*/
static const struct trans_tbl route_metrices[] = {
- __ADD(RTAX_UNSPEC, unspec)
- __ADD(RTAX_LOCK, lock)
- __ADD(RTAX_MTU, mtu)
- __ADD(RTAX_WINDOW, window)
- __ADD(RTAX_RTT, rtt)
- __ADD(RTAX_RTTVAR, rttvar)
- __ADD(RTAX_SSTHRESH, ssthresh)
- __ADD(RTAX_CWND, cwnd)
- __ADD(RTAX_ADVMSS, advmss)
- __ADD(RTAX_REORDERING, reordering)
- __ADD(RTAX_HOPLIMIT, hoplimit)
- __ADD(RTAX_INITCWND, initcwnd)
- __ADD(RTAX_FEATURES, features)
+ __ADD(RTAX_UNSPEC, unspec),
+ __ADD(RTAX_LOCK, lock),
+ __ADD(RTAX_MTU, mtu),
+ __ADD(RTAX_WINDOW, window),
+ __ADD(RTAX_RTT, rtt),
+ __ADD(RTAX_RTTVAR, rttvar),
+ __ADD(RTAX_SSTHRESH, ssthresh),
+ __ADD(RTAX_CWND, cwnd),
+ __ADD(RTAX_ADVMSS, advmss),
+ __ADD(RTAX_REORDERING, reordering),
+ __ADD(RTAX_HOPLIMIT, hoplimit),
+ __ADD(RTAX_INITCWND, initcwnd),
+ __ADD(RTAX_FEATURES, features),
};
char *rtnl_route_metric2str(int metric, char *buf, size_t size)
diff --git a/lib/route/rtnl.c b/lib/route/rtnl.c
index 6a55ca1a..f280a489 100644
--- a/lib/route/rtnl.c
+++ b/lib/route/rtnl.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/rtnl.c Routing Netlink
*
@@ -34,9 +35,9 @@
* Fills out a routing netlink request message and sends it out
* using nl_send_simple().
*
- * @return 0 on success or a negative error code. Due to a bug in
- * older versions, this returned the number of bytes sent. So for
- * compatibility, treat positive return values as success too.
+ * @return 0 on success or a negative error code. Due to a bug in older
+ * version of the library, this function returned the number of bytes sent.
+ * Treat any non-negative number as success.
*/
int nl_rtgen_request(struct nl_sock *sk, int type, int family, int flags)
{
@@ -58,18 +59,18 @@ int nl_rtgen_request(struct nl_sock *sk, int type, int family, int flags)
*/
static const struct trans_tbl rtntypes[] = {
- __ADD(RTN_UNSPEC,unspec)
- __ADD(RTN_UNICAST,unicast)
- __ADD(RTN_LOCAL,local)
- __ADD(RTN_BROADCAST,broadcast)
- __ADD(RTN_ANYCAST,anycast)
- __ADD(RTN_MULTICAST,multicast)
- __ADD(RTN_BLACKHOLE,blackhole)
- __ADD(RTN_UNREACHABLE,unreachable)
- __ADD(RTN_PROHIBIT,prohibit)
- __ADD(RTN_THROW,throw)
- __ADD(RTN_NAT,nat)
- __ADD(RTN_XRESOLVE,xresolve)
+ __ADD(RTN_UNSPEC,unspec),
+ __ADD(RTN_UNICAST,unicast),
+ __ADD(RTN_LOCAL,local),
+ __ADD(RTN_BROADCAST,broadcast),
+ __ADD(RTN_ANYCAST,anycast),
+ __ADD(RTN_MULTICAST,multicast),
+ __ADD(RTN_BLACKHOLE,blackhole),
+ __ADD(RTN_UNREACHABLE,unreachable),
+ __ADD(RTN_PROHIBIT,prohibit),
+ __ADD(RTN_THROW,throw),
+ __ADD(RTN_NAT,nat),
+ __ADD(RTN_XRESOLVE,xresolve),
};
char *nl_rtntype2str(int type, char *buf, size_t size)
@@ -90,11 +91,11 @@ int nl_str2rtntype(const char *name)
*/
static const struct trans_tbl scopes[] = {
- __ADD(255,nowhere)
- __ADD(254,host)
- __ADD(253,link)
- __ADD(200,site)
- __ADD(0,global)
+ __ADD(255,nowhere),
+ __ADD(254,host),
+ __ADD(253,link),
+ __ADD(200,site),
+ __ADD(0,global),
};
char *rtnl_scope2str(int scope, char *buf, size_t size)
diff --git a/lib/route/rule.c b/lib/route/rule.c
index b2161a2e..a0ba42ea 100644
--- a/lib/route/rule.c
+++ b/lib/route/rule.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/rule.c Routing Rules
*
@@ -22,22 +23,28 @@
#include <netlink/route/rtnl.h>
#include <netlink/route/rule.h>
#include <inttypes.h>
+#include <linux/fib_rules.h>
/** @cond SKIP */
-#define RULE_ATTR_FAMILY 0x0001
-#define RULE_ATTR_TABLE 0x0002
-#define RULE_ATTR_ACTION 0x0004
-#define RULE_ATTR_FLAGS 0x0008
-#define RULE_ATTR_IIFNAME 0x0010
-#define RULE_ATTR_OIFNAME 0x0020
-#define RULE_ATTR_PRIO 0x0040
-#define RULE_ATTR_MARK 0x0080
-#define RULE_ATTR_MASK 0x0100
-#define RULE_ATTR_GOTO 0x0200
-#define RULE_ATTR_SRC 0x0400
-#define RULE_ATTR_DST 0x0800
-#define RULE_ATTR_DSFIELD 0x1000
-#define RULE_ATTR_FLOW 0x2000
+#define RULE_ATTR_FAMILY 0x000001
+#define RULE_ATTR_TABLE 0x000002
+#define RULE_ATTR_ACTION 0x000004
+#define RULE_ATTR_FLAGS 0x000008
+#define RULE_ATTR_IIFNAME 0x000010
+#define RULE_ATTR_OIFNAME 0x000020
+#define RULE_ATTR_PRIO 0x000040
+#define RULE_ATTR_MARK 0x000080
+#define RULE_ATTR_MASK 0x000100
+#define RULE_ATTR_GOTO 0x000200
+#define RULE_ATTR_SRC 0x000400
+#define RULE_ATTR_DST 0x000800
+#define RULE_ATTR_DSFIELD 0x001000
+#define RULE_ATTR_FLOW 0x002000
+#define RULE_ATTR_L3MDEV 0x004000
+#define RULE_ATTR_PROTOCOL 0x008000
+#define RULE_ATTR_IP_PROTO 0x010000
+#define RULE_ATTR_SPORT 0x020000
+#define RULE_ATTR_DPORT 0x040000
static struct nl_cache_ops rtnl_rule_ops;
static struct nl_object_ops rule_obj_ops;
@@ -79,6 +86,13 @@ static struct nla_policy rule_policy[FRA_MAX+1] = {
[FRA_FWMASK] = { .type = NLA_U32 },
[FRA_GOTO] = { .type = NLA_U32 },
[FRA_FLOW] = { .type = NLA_U32 },
+ [FRA_L3MDEV] = { .type = NLA_U8 },
+ [FRA_PROTOCOL] = { .type = NLA_U8 },
+ [FRA_IP_PROTO] = { .type = NLA_U8 },
+ [FRA_SPORT_RANGE] = { .minlen = sizeof(struct fib_rule_port_range),
+ .maxlen = sizeof(struct fib_rule_port_range) },
+ [FRA_DPORT_RANGE] = { .minlen = sizeof(struct fib_rule_port_range),
+ .maxlen = sizeof(struct fib_rule_port_range) },
};
static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
@@ -107,8 +121,9 @@ static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
rule->r_action = frh->action;
rule->r_flags = frh->flags;
- rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TABLE | RULE_ATTR_ACTION |
- RULE_ATTR_FLAGS);
+ rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_ACTION | RULE_ATTR_FLAGS);
+ if (rule->r_table)
+ rule->ce_mask |= RULE_ATTR_TABLE;
/* ipv4 only */
if (frh->tos) {
@@ -118,7 +133,8 @@ static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
if (tb[FRA_TABLE]) {
rule->r_table = nla_get_u32(tb[FRA_TABLE]);
- rule->ce_mask |= RULE_ATTR_TABLE;
+ if (rule->r_table)
+ rule->ce_mask |= RULE_ATTR_TABLE;
}
if (tb[FRA_IIFNAME]) {
@@ -172,6 +188,37 @@ static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
rule->ce_mask |= RULE_ATTR_FLOW;
}
+ if (tb[FRA_L3MDEV]) {
+ rule->r_l3mdev = nla_get_u8(tb[FRA_L3MDEV]);
+ rule->ce_mask |= RULE_ATTR_L3MDEV;
+ }
+
+ if (tb[FRA_PROTOCOL]) {
+ rule->r_protocol = nla_get_u8(tb[FRA_PROTOCOL]);
+ rule->ce_mask |= RULE_ATTR_PROTOCOL;
+ }
+
+ if (tb[FRA_IP_PROTO]) {
+ rule->r_ip_proto = nla_get_u8(tb[FRA_IP_PROTO]);
+ rule->ce_mask |= RULE_ATTR_IP_PROTO;
+ }
+
+ if (tb[FRA_SPORT_RANGE]) {
+ struct fib_rule_port_range *pr;
+
+ pr = nla_data(tb[FRA_SPORT_RANGE]);
+ rule->r_sport = *pr;
+ rule->ce_mask |= RULE_ATTR_SPORT;
+ }
+
+ if (tb[FRA_DPORT_RANGE]) {
+ struct fib_rule_port_range *pr;
+
+ pr = nla_data(tb[FRA_DPORT_RANGE]);
+ rule->r_dport = *pr;
+ rule->ce_mask |= RULE_ATTR_DPORT;
+ }
+
err = pp->pp_cb((struct nl_object *) rule, pp);
errout:
rtnl_rule_put(rule);
@@ -219,6 +266,33 @@ static void rule_dump_line(struct nl_object *o, struct nl_dump_params *p)
nl_dump(p, "lookup %s ",
rtnl_route_table2str(r->r_table, buf, sizeof(buf)));
+ if (r->ce_mask & RULE_ATTR_L3MDEV)
+ nl_dump(p, "lookup [l3mdev-table] ");
+
+ if (r->ce_mask & RULE_ATTR_IP_PROTO)
+ nl_dump(p, "ipproto %s ",
+ nl_ip_proto2str(r->r_ip_proto, buf, sizeof(buf)));
+
+ if (r->ce_mask & RULE_ATTR_SPORT) {
+ if (r->r_sport.start == r->r_sport.end)
+ nl_dump(p, "sport %u ", r->r_sport.start);
+ else
+ nl_dump(p, "sport %u-%u ",
+ r->r_sport.start, r->r_sport.end);
+ }
+
+ if (r->ce_mask & RULE_ATTR_DPORT) {
+ if (r->r_dport.start == r->r_dport.end)
+ nl_dump(p, "dport %u ", r->r_dport.start);
+ else
+ nl_dump(p, "dport %u-%u ",
+ r->r_dport.start, r->r_dport.end);
+ }
+
+ if (r->ce_mask & RULE_ATTR_PROTOCOL)
+ nl_dump(p, "protocol %s ",
+ rtnl_route_proto2str(r->r_protocol, buf, sizeof(buf)));
+
if (r->ce_mask & RULE_ATTR_FLOW)
nl_dump(p, "flow %s ",
rtnl_realms2str(r->r_flow, buf, sizeof(buf)));
@@ -243,14 +317,12 @@ static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
rule_dump_details(obj, p);
}
-#define RULE_ATTR_FLAGS 0x0008
-
-static int rule_compare(struct nl_object *_a, struct nl_object *_b,
- uint32_t attrs, int flags)
+static uint64_t rule_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
{
struct rtnl_rule *a = (struct rtnl_rule *) _a;
struct rtnl_rule *b = (struct rtnl_rule *) _b;
- int diff = 0;
+ uint64_t diff = 0;
#define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR)
@@ -274,19 +346,19 @@ static int rule_compare(struct nl_object *_a, struct nl_object *_b,
}
static const struct trans_tbl rule_attrs[] = {
- __ADD(RULE_ATTR_FAMILY, family)
- __ADD(RULE_ATTR_TABLE, table)
- __ADD(RULE_ATTR_ACTION, action)
- __ADD(RULE_ATTR_IIFNAME, iifname)
- __ADD(RULE_ATTR_OIFNAME, oifname)
- __ADD(RULE_ATTR_PRIO, prio)
- __ADD(RULE_ATTR_MARK, mark)
- __ADD(RULE_ATTR_MASK, mask)
- __ADD(RULE_ATTR_GOTO, goto)
- __ADD(RULE_ATTR_SRC, src)
- __ADD(RULE_ATTR_DST, dst)
- __ADD(RULE_ATTR_DSFIELD, dsfield)
- __ADD(RULE_ATTR_FLOW, flow)
+ __ADD(RULE_ATTR_FAMILY, family),
+ __ADD(RULE_ATTR_TABLE, table),
+ __ADD(RULE_ATTR_ACTION, action),
+ __ADD(RULE_ATTR_IIFNAME, iifname),
+ __ADD(RULE_ATTR_OIFNAME, oifname),
+ __ADD(RULE_ATTR_PRIO, prio),
+ __ADD(RULE_ATTR_MARK, mark),
+ __ADD(RULE_ATTR_MASK, mask),
+ __ADD(RULE_ATTR_GOTO, goto),
+ __ADD(RULE_ATTR_SRC, src),
+ __ADD(RULE_ATTR_DST, dst),
+ __ADD(RULE_ATTR_DSFIELD, dsfield),
+ __ADD(RULE_ATTR_FLOW, flow),
};
static char *rule_attrs2str(int attrs, char *buf, size_t len)
@@ -414,6 +486,22 @@ static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags,
if (tmpl->ce_mask & RULE_ATTR_FLOW)
NLA_PUT_U32(msg, FRA_FLOW, tmpl->r_flow);
+ if (tmpl->ce_mask & RULE_ATTR_L3MDEV)
+ NLA_PUT_U8(msg, FRA_L3MDEV, tmpl->r_l3mdev);
+
+ if (tmpl->ce_mask & RULE_ATTR_IP_PROTO)
+ NLA_PUT_U8(msg, FRA_IP_PROTO, tmpl->r_ip_proto);
+
+ if (tmpl->ce_mask & RULE_ATTR_SPORT)
+ NLA_PUT(msg, FRA_SPORT_RANGE, sizeof(tmpl->r_sport),
+ &tmpl->r_sport);
+
+ if (tmpl->ce_mask & RULE_ATTR_DPORT)
+ NLA_PUT(msg, FRA_DPORT_RANGE, sizeof(tmpl->r_dport),
+ &tmpl->r_dport);
+
+ if (tmpl->ce_mask & RULE_ATTR_PROTOCOL)
+ NLA_PUT_U8(msg, FRA_PROTOCOL, tmpl->r_protocol);
*result = msg;
return 0;
@@ -690,6 +778,152 @@ uint8_t rtnl_rule_get_action(struct rtnl_rule *rule)
return rule->r_action;
}
+/**
+ * Set l3mdev value of the rule (FRA_L3MDEV)
+ * @arg rule rule
+ * @arg value value to set
+ *
+ * Set the l3mdev value to value. Currently supported values
+ * are only 1 (set it) and -1 (unset it). All other values
+ * are reserved.
+ */
+void rtnl_rule_set_l3mdev(struct rtnl_rule *rule, int value)
+{
+ if (value >= 0) {
+ rule->r_l3mdev = (uint8_t) value;
+ rule->ce_mask |= RULE_ATTR_L3MDEV;
+ } else {
+ rule->r_l3mdev = 0;
+ rule->ce_mask &= ~((uint32_t) RULE_ATTR_L3MDEV);
+ }
+}
+
+/**
+ * Get l3mdev value of the rule (FRA_L3MDEV)
+ * @arg rule rule
+ *
+ * @return a negative error code, including -NLE_MISSING_ATTR
+ * if the property is unset. Otherwise returns a non-negative
+ * value. As FRA_L3MDEV is a boolean, the only expected
+ * value at the moment is 1.
+ */
+int rtnl_rule_get_l3mdev(struct rtnl_rule *rule)
+{
+ if (!rule)
+ return -NLE_INVAL;
+ if (!(rule->ce_mask & RULE_ATTR_L3MDEV))
+ return -NLE_MISSING_ATTR;
+ return rule->r_l3mdev;
+}
+
+int rtnl_rule_set_protocol(struct rtnl_rule *rule, uint8_t protocol)
+{
+ if (protocol) {
+ rule->r_protocol = protocol;
+ rule->ce_mask |= RULE_ATTR_PROTOCOL;
+ } else {
+ rule->r_protocol = 0;
+ rule->ce_mask &= ~((uint32_t) RULE_ATTR_PROTOCOL);
+ }
+ return 0;
+}
+
+int rtnl_rule_get_protocol(struct rtnl_rule *rule, uint8_t *protocol)
+{
+ if (!(rule->ce_mask & RULE_ATTR_PROTOCOL))
+ return -NLE_INVAL;
+
+ *protocol = rule->r_protocol;
+ return 0;
+}
+
+int rtnl_rule_set_ipproto(struct rtnl_rule *rule, uint8_t ip_proto)
+{
+ if (ip_proto) {
+ rule->r_ip_proto = ip_proto;
+ rule->ce_mask |= RULE_ATTR_IP_PROTO;
+ } else {
+ rule->r_ip_proto = 0;
+ rule->ce_mask &= ~((uint32_t) RULE_ATTR_IP_PROTO);
+ }
+ return 0;
+}
+
+int rtnl_rule_get_ipproto(struct rtnl_rule *rule, uint8_t *ip_proto)
+{
+ if (!(rule->ce_mask & RULE_ATTR_IP_PROTO))
+ return -NLE_INVAL;
+
+ *ip_proto = rule->r_ip_proto;
+ return 0;
+}
+
+static int __rtnl_rule_set_port(struct fib_rule_port_range *prange,
+ uint16_t start, uint16_t end,
+ uint64_t attr, uint64_t *mask)
+{
+ if ((start && end < start) || (end && !start))
+ return -NLE_INVAL;
+
+ if (start) {
+ prange->start = start;
+ prange->end = end;
+ *mask |= attr;
+ } else {
+ prange->start = 0;
+ prange->end = 0;
+ *mask &= ~attr;
+
+ }
+ return 0;
+}
+
+int rtnl_rule_set_sport(struct rtnl_rule *rule, uint16_t sport)
+{
+ return __rtnl_rule_set_port(&rule->r_sport, sport, sport,
+ RULE_ATTR_SPORT, &rule->ce_mask);
+}
+
+int rtnl_rule_set_sport_range(struct rtnl_rule *rule, uint16_t start,
+ uint16_t end)
+{
+ return __rtnl_rule_set_port(&rule->r_sport, start, end,
+ RULE_ATTR_SPORT, &rule->ce_mask);
+}
+
+int rtnl_rule_get_sport(struct rtnl_rule *rule, uint16_t *start, uint16_t *end)
+{
+ if (!(rule->ce_mask & RULE_ATTR_SPORT))
+ return -NLE_INVAL;
+
+ *start = rule->r_sport.start;
+ *end = rule->r_sport.end;
+ return 0;
+}
+
+int rtnl_rule_set_dport(struct rtnl_rule *rule, uint16_t dport)
+{
+ return __rtnl_rule_set_port(&rule->r_dport, dport, dport,
+ RULE_ATTR_DPORT, &rule->ce_mask);
+}
+
+int rtnl_rule_set_dport_range(struct rtnl_rule *rule, uint16_t start,
+ uint16_t end)
+{
+ return __rtnl_rule_set_port(&rule->r_dport, start, end,
+ RULE_ATTR_DPORT, &rule->ce_mask);
+}
+
+int rtnl_rule_get_dport(struct rtnl_rule *rule, uint16_t *start, uint16_t *end)
+{
+ if (!(rule->ce_mask & RULE_ATTR_DPORT))
+ return -NLE_INVAL;
+
+ *start = rule->r_dport.start;
+ *end = rule->r_dport.end;
+ return 0;
+}
+
void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms)
{
rule->r_flow = realms;
@@ -729,6 +963,12 @@ static struct nl_object_ops rule_obj_ops = {
.oo_id_attrs = ~0,
};
+static struct nl_af_group rule_groups[] = {
+ { AF_INET, RTNLGRP_IPV4_RULE },
+ { AF_INET6, RTNLGRP_IPV6_RULE },
+ { END_OF_GROUP_LIST },
+};
+
static struct nl_cache_ops rtnl_rule_ops = {
.co_name = "route/rule",
.co_hdrsize = sizeof(struct fib_rule_hdr),
@@ -742,6 +982,7 @@ static struct nl_cache_ops rtnl_rule_ops = {
.co_request_update = rule_request_update,
.co_msg_parser = rule_msg_parser,
.co_obj_ops = &rule_obj_ops,
+ .co_groups = rule_groups,
};
static void __init rule_init(void)
diff --git a/lib/route/tc.c b/lib/route/tc.c
index 0f150cca..35303f59 100644
--- a/lib/route/tc.c
+++ b/lib/route/tc.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/route/tc.c Traffic Control
*
@@ -24,6 +25,8 @@
#include <netlink/route/tc.h>
#include <netlink-private/route/tc-api.h>
+#include "netlink-private/utils.h"
+
/** @cond SKIP */
static struct nl_list_head tc_ops_list[__RTNL_TC_TYPE_MAX];
@@ -32,12 +35,13 @@ static struct rtnl_tc_type_ops *tc_type_ops[__RTNL_TC_TYPE_MAX];
static struct nla_policy tc_policy[TCA_MAX+1] = {
[TCA_KIND] = { .type = NLA_STRING,
.maxlen = TCKINDSIZ },
+ [TCA_CHAIN] = { .type = NLA_U32 },
[TCA_STATS] = { .minlen = sizeof(struct tc_stats) },
[TCA_STATS2] = { .type = NLA_NESTED },
};
int tca_parse(struct nlattr **tb, int maxattr, struct rtnl_tc *g,
- struct nla_policy *policy)
+ const struct nla_policy *policy)
{
if (g->ce_mask & TCA_ATTR_OPTS)
@@ -79,6 +83,9 @@ int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc)
nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind));
rtnl_tc_set_kind(tc, kind);
+ if (tb[TCA_CHAIN])
+ rtnl_tc_set_chain(tc, nla_get_u32(tb[TCA_CHAIN]));
+
tm = nlmsg_data(n);
tc->tc_family = tm->tcm_family;
tc->tc_ifindex = tm->tcm_ifindex;
@@ -137,6 +144,7 @@ int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc)
tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]);
if (tc->tc_xstats == NULL)
return -NLE_NOMEM;
+ tc->ce_mask |= TCA_ATTR_XSTATS;
} else
goto compat_xstats;
} else {
@@ -201,17 +209,22 @@ int rtnl_tc_msg_build(struct rtnl_tc *tc, int type, int flags,
.tcm_handle = tc->tc_handle,
.tcm_parent = tc->tc_parent,
};
- int err = -NLE_MSGSIZE;
+ int err;
msg = nlmsg_alloc_simple(type, flags);
if (!msg)
return -NLE_NOMEM;
- if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0)
- goto nla_put_failure;
+ if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
+ err = -NLE_MSGSIZE;
+ goto out_err;
+ }
if (tc->ce_mask & TCA_ATTR_KIND)
- NLA_PUT_STRING(msg, TCA_KIND, tc->tc_kind);
+ NLA_PUT_STRING(msg, TCA_KIND, tc->tc_kind);
+
+ if (tc->ce_mask & TCA_ATTR_CHAIN)
+ NLA_PUT_U32(msg, TCA_CHAIN, tc->tc_chain);
ops = rtnl_tc_get_ops(tc);
if (ops && (ops->to_msg_fill || ops->to_msg_fill_raw)) {
@@ -219,31 +232,32 @@ int rtnl_tc_msg_build(struct rtnl_tc *tc, int type, int flags,
void *data = rtnl_tc_data(tc);
if (ops->to_msg_fill) {
- if (!(opts = nla_nest_start(msg, TCA_OPTIONS)))
- goto nla_put_failure;
+ if (!(opts = nla_nest_start(msg, TCA_OPTIONS))) {
+ err = -NLE_NOMEM;
+ goto out_err;
+ }
if ((err = ops->to_msg_fill(tc, data, msg)) < 0)
- goto nla_put_failure;
+ goto out_err;
- nla_nest_end(msg, opts);
+ if (strcmp("cgroup", tc->tc_kind))
+ nla_nest_end(msg, opts);
+ else
+ nla_nest_end_keep_empty(msg, opts);
} else if ((err = ops->to_msg_fill_raw(tc, data, msg)) < 0)
- goto nla_put_failure;
+ goto out_err;
}
*result = msg;
return 0;
nla_put_failure:
+ err = -NLE_NOMEM;
+out_err:
nlmsg_free(msg);
return err;
}
-void tca_set_kind(struct rtnl_tc *t, const char *kind)
-{
- strncpy(t->tc_kind, kind, sizeof(t->tc_kind) - 1);
- t->ce_mask |= TCA_ATTR_KIND;
-}
-
/** @endcond */
@@ -518,7 +532,12 @@ int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind)
if (tc->ce_mask & TCA_ATTR_KIND)
return -NLE_EXIST;
- strncpy(tc->tc_kind, kind, sizeof(tc->tc_kind) - 1);
+ if ( !kind
+ || strlen (kind) >= sizeof (tc->tc_kind))
+ return -NLE_INVAL;
+
+ _nl_strncpy(tc->tc_kind, kind, sizeof(tc->tc_kind));
+
tc->ce_mask |= TCA_ATTR_KIND;
/* Force allocation of data */
@@ -550,12 +569,40 @@ char *rtnl_tc_get_kind(struct rtnl_tc *tc)
*/
uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id)
{
- if (id < 0 || id > RTNL_TC_STATS_MAX)
+ if ((unsigned int) id > RTNL_TC_STATS_MAX)
return 0;
return tc->tc_stats[id];
}
+/**
+ * Set the chain index of a traffic control object
+ * @arg tc traffic control object
+ * @arg chain chain index of traffic control object
+ *
+ */
+void rtnl_tc_set_chain(struct rtnl_tc *tc, uint32_t chain)
+{
+ tc->tc_chain = chain;
+ tc->ce_mask |= TCA_ATTR_CHAIN;
+}
+
+/**
+ * Return chain index of traffic control object
+ * @arg tc traffic control object
+ * @arg out_value output argument.
+ *
+ * @return 0 of the output value was successfully returned, or a negative
+ * error code on failure.
+ */
+int rtnl_tc_get_chain(struct rtnl_tc *tc, uint32_t *out_value)
+{
+ if (!(tc->ce_mask & TCA_ATTR_CHAIN))
+ return -NLE_MISSING_ATTR;
+ *out_value = tc->tc_chain;
+ return 0;
+}
+
/** @} */
/**
@@ -563,6 +610,28 @@ uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id)
* @{
*/
+static const struct trans_tbl tc_stats[] = {
+ __ADD(RTNL_TC_PACKETS, packets),
+ __ADD(RTNL_TC_BYTES, bytes),
+ __ADD(RTNL_TC_RATE_BPS, rate_bps),
+ __ADD(RTNL_TC_RATE_PPS, rate_pps),
+ __ADD(RTNL_TC_QLEN, qlen),
+ __ADD(RTNL_TC_BACKLOG, backlog),
+ __ADD(RTNL_TC_DROPS, drops),
+ __ADD(RTNL_TC_REQUEUES, requeues),
+ __ADD(RTNL_TC_OVERLIMITS, overlimits),
+};
+
+char *rtnl_tc_stat2str(enum rtnl_tc_stat st, char *buf, size_t len)
+{
+ return __type2str(st, buf, len, tc_stats, ARRAY_SIZE(tc_stats));
+}
+
+int rtnl_tc_str2stat(const char *name)
+{
+ return __str2type(name, tc_stats, ARRAY_SIZE(tc_stats));
+}
+
/**
* Calculate time required to transmit buffer at a specific rate
* @arg bufsize Size of buffer to be transmited in bytes.
@@ -579,11 +648,7 @@ uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id)
*/
int rtnl_tc_calc_txtime(int bufsize, int rate)
{
- double tx_time_secs;
-
- tx_time_secs = (double) bufsize / (double) rate;
-
- return tx_time_secs * 1000000.;
+ return ((double) bufsize / (double) rate) * 1000000.0;
}
/**
@@ -602,11 +667,7 @@ int rtnl_tc_calc_txtime(int bufsize, int rate)
*/
int rtnl_tc_calc_bufsize(int txtime, int rate)
{
- double bufsize;
-
- bufsize = (double) txtime * (double) rate;
-
- return bufsize / 1000000.;
+ return ((double) txtime * (double) rate) / 1000000.0;
}
/**
@@ -715,7 +776,7 @@ int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec,
for (i = 0; i < RTNL_TC_RTABLE_SIZE; i++) {
size = adjust_size((i + 1) << cell_log, spec->rs_mpu, linktype);
- dst[i] = nl_us2ticks(rtnl_tc_calc_txtime(size, spec->rs_rate));
+ dst[i] = nl_us2ticks(rtnl_tc_calc_txtime64(size, spec->rs_rate64));
}
spec->rs_cell_align = -1;
@@ -759,16 +820,24 @@ int rtnl_tc_clone(struct nl_object *dstobj, struct nl_object *srcobj)
dst->tc_link = src->tc_link;
}
+ dst->tc_opts = NULL;
+ dst->tc_xstats = NULL;
+ dst->tc_subdata = NULL;
+ dst->ce_mask &= ~(TCA_ATTR_OPTS |
+ TCA_ATTR_XSTATS);
+
if (src->tc_opts) {
dst->tc_opts = nl_data_clone(src->tc_opts);
if (!dst->tc_opts)
return -NLE_NOMEM;
+ dst->ce_mask |= TCA_ATTR_OPTS;
}
-
+
if (src->tc_xstats) {
dst->tc_xstats = nl_data_clone(src->tc_xstats);
if (!dst->tc_xstats)
return -NLE_NOMEM;
+ dst->ce_mask |= TCA_ATTR_XSTATS;
}
if (src->tc_subdata) {
@@ -872,47 +941,41 @@ void rtnl_tc_dump_details(struct nl_object *obj, struct nl_dump_params *p)
void rtnl_tc_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
{
struct rtnl_tc *tc = TC_CAST(obj);
- char *unit, fmt[64];
+ char *unit;
float res;
rtnl_tc_dump_details(OBJ_CAST(tc), p);
- strcpy(fmt, " %7.2f %s %10u %10u %10u %10u %10u\n");
-
- nl_dump_line(p,
- " Stats: bytes packets drops overlimits" \
- " qlen backlog\n");
+ nl_dump_line(p,
+ " stats: %-14s %-10s %-10s %-10s %-10s %-10s\n",
+ "bytes", "packets", "drops", "overlimits", "qlen", "backlog");
res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_BYTES], &unit);
- if (*unit == 'B')
- fmt[11] = '9';
- nl_dump_line(p, fmt, res, unit,
- tc->tc_stats[RTNL_TC_PACKETS],
- tc->tc_stats[RTNL_TC_DROPS],
- tc->tc_stats[RTNL_TC_OVERLIMITS],
- tc->tc_stats[RTNL_TC_QLEN],
- tc->tc_stats[RTNL_TC_BACKLOG]);
+ nl_dump_line(p,
+ " %10.2f %3s %10u %-10u %-10u %-10u %-10u\n",
+ res, unit,
+ tc->tc_stats[RTNL_TC_PACKETS],
+ tc->tc_stats[RTNL_TC_DROPS],
+ tc->tc_stats[RTNL_TC_OVERLIMITS],
+ tc->tc_stats[RTNL_TC_QLEN],
+ tc->tc_stats[RTNL_TC_BACKLOG]);
res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_RATE_BPS], &unit);
- strcpy(fmt, " %7.2f %s/s%9u pps");
-
- if (*unit == 'B')
- fmt[11] = '9';
-
- nl_dump_line(p, fmt, res, unit, tc->tc_stats[RTNL_TC_RATE_PPS]);
-
- tc_dump(tc, NL_DUMP_LINE, p);
- nl_dump(p, "\n");
+ nl_dump_line(p,
+ " %10.2f %3s/s %10u/s\n",
+ res,
+ unit,
+ tc->tc_stats[RTNL_TC_RATE_PPS]);
}
-int rtnl_tc_compare(struct nl_object *aobj, struct nl_object *bobj,
- uint32_t attrs, int flags)
+uint64_t rtnl_tc_compare(struct nl_object *aobj, struct nl_object *bobj,
+ uint64_t attrs, int flags)
{
struct rtnl_tc *a = TC_CAST(aobj);
struct rtnl_tc *b = TC_CAST(bobj);
- int diff = 0;
+ uint64_t diff = 0;
#define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR)
@@ -995,6 +1058,19 @@ void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
}
/**
+ * Returns the private data of the traffic control object.
+ * Contrary to rtnl_tc_data(), this returns NULL if the data is
+ * not yet allocated
+ * @arg tc traffic control object
+ *
+ * @return pointer to the private data or NULL if not allocated.
+ */
+void *rtnl_tc_data_peek(struct rtnl_tc *tc)
+{
+ return tc->tc_subdata ? nl_data_get(tc->tc_subdata) : NULL;
+}
+
+/**
* Return pointer to private data of traffic control object
* @arg tc traffic control object
*
@@ -1009,9 +1085,6 @@ void *rtnl_tc_data(struct rtnl_tc *tc)
size_t size;
if (!tc->tc_ops) {
- if (!tc->tc_kind)
- BUG();
-
if (!rtnl_tc_get_ops(tc))
return NULL;
}
@@ -1030,6 +1103,7 @@ void *rtnl_tc_data(struct rtnl_tc *tc)
* Check traffic control object type and return private data section
* @arg tc traffic control object
* @arg ops expected traffic control object operations
+ * @arg err the place where saves the error code if fails
*
* Checks whether the traffic control object matches the type
* specified with the traffic control object operations. If the
@@ -1040,8 +1114,10 @@ void *rtnl_tc_data(struct rtnl_tc *tc)
*
* @return Pointer to private tc data or NULL if type mismatches.
*/
-void *rtnl_tc_data_check(struct rtnl_tc *tc, struct rtnl_tc_ops *ops)
+void *rtnl_tc_data_check(struct rtnl_tc *tc, struct rtnl_tc_ops *ops, int *err)
{
+ void *ret;
+
if (tc->tc_ops != ops) {
char buf[64];
@@ -1050,10 +1126,18 @@ void *rtnl_tc_data_check(struct rtnl_tc *tc, struct rtnl_tc_ops *ops)
tc, ops->to_kind, tc->tc_ops->to_kind);
APPBUG(buf);
+ if (err)
+ *err = -NLE_OPNOTSUPP;
return NULL;
}
- return rtnl_tc_data(tc);
+ ret = rtnl_tc_data(tc);
+ if (ret == NULL) {
+ if (err)
+ *err = -NLE_NOMEM;
+ }
+
+ return ret;
}
struct nl_af_group tc_groups[] = {
diff --git a/lib/socket.c b/lib/socket.c
index 5f61b382..cfb07437 100644
--- a/lib/socket.c
+++ b/lib/socket.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/socket.c Netlink Socket
*
@@ -29,8 +30,11 @@
#include "defs.h"
+#include "sys/socket.h"
+
#include <netlink-private/netlink.h>
#include <netlink-private/socket.h>
+#include <netlink-private/utils.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/handlers.h>
@@ -106,15 +110,14 @@ static uint32_t generate_local_port(void)
nl_write_unlock(&port_map_lock);
- return pid + (((uint32_t)n) << 22);
+ /* ensure we don't return zero. */
+ pid = pid + (((uint32_t)n) << 22);
+ return pid ? pid : 1024;
}
}
nl_write_unlock(&port_map_lock);
-
- /* Out of sockets in our own PID namespace, what to do? FIXME */
- NL_DBG(1, "Warning: Ran out of unique local port namespace\n");
- return UINT32_MAX;
+ return 0;
}
static void release_local_port(uint32_t port)
@@ -122,9 +125,6 @@ static void release_local_port(uint32_t port)
int nr;
uint32_t mask;
- if (port == UINT32_MAX)
- return;
-
BUG_ON(port == 0);
nr = port >> 22;
@@ -165,7 +165,7 @@ void _nl_socket_used_ports_set(uint32_t *used_ports, uint32_t port)
nr /= 32;
/*
- BUG_ON(port == UINT32_MAX || port == 0 || (getpid() & 0x3FFFFF) != (port & 0x3FFFFF));
+ BUG_ON(port == 0 || (getpid() & 0x3FFFFF) != (port & 0x3FFFFF));
BUG_ON(used_ports[nr] & mask);
*/
@@ -190,7 +190,7 @@ static struct nl_sock *__alloc_socket(struct nl_cb *cb)
sk->s_cb = nl_cb_get(cb);
sk->s_local.nl_family = AF_NETLINK;
sk->s_peer.nl_family = AF_NETLINK;
- sk->s_seq_expect = sk->s_seq_next = time(0);
+ sk->s_seq_expect = sk->s_seq_next = time(NULL);
/* the port is 0 (unspecified), meaning NL_OWN_PORT */
sk->s_flags = NL_OWN_PORT;
@@ -206,18 +206,18 @@ static struct nl_sock *__alloc_socket(struct nl_cb *cb)
struct nl_sock *nl_socket_alloc(void)
{
struct nl_cb *cb;
- struct nl_sock *sk;
+ struct nl_sock *sk;
cb = nl_cb_alloc(default_cb);
if (!cb)
return NULL;
- /* will increment cb reference count on success */
+ /* will increment cb reference count on success */
sk = __alloc_socket(cb);
- nl_cb_put(cb);
+ nl_cb_put(cb);
- return sk;
+ return sk;
}
/**
@@ -335,16 +335,24 @@ int _nl_socket_is_local_port_unspecified(struct nl_sock *sk)
return (sk->s_local.nl_pid == 0);
}
-uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk)
+uint32_t _nl_socket_set_local_port_no_release(struct nl_sock *sk, int generate_other)
{
uint32_t port;
/* reset the port to generate_local_port(), but do not release
* the previously generated port. */
- port = generate_local_port();
- sk->s_flags &= ~NL_OWN_PORT;
+ if (generate_other)
+ port = generate_local_port();
+ else
+ port = 0;
sk->s_local.nl_pid = port;
+ if (port == 0) {
+ /* failed to find an unsed port. Restore the socket to have an
+ * unspecified port. */
+ sk->s_flags |= NL_OWN_PORT;
+ } else
+ sk->s_flags &= ~NL_OWN_PORT;
return port;
}
/** \endcond */
@@ -357,6 +365,8 @@ uint32_t _nl_socket_generate_local_port_no_release(struct nl_sock *sk)
uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
{
if (sk->s_local.nl_pid == 0) {
+ struct nl_sock *sk_mutable = (struct nl_sock *) sk;
+
/* modify the const argument sk. This is justified, because
* nobody ever saw the local_port from externally. So, we
* initilize it on first use.
@@ -366,7 +376,15 @@ uint32_t nl_socket_get_local_port(const struct nl_sock *sk)
* is not automatically threadsafe anyway, so the user is not
* allowed to do that.
*/
- return _nl_socket_generate_local_port_no_release((struct nl_sock *) sk);
+ sk_mutable->s_local.nl_pid = generate_local_port();
+ if (sk_mutable->s_local.nl_pid == 0) {
+ /* could not generate a local port. Assign UINT32_MAX to preserve
+ * backward compatibility. A user who cares can clear that anyway
+ * with nl_socket_set_local_port(). */
+ sk_mutable->s_local.nl_pid = UINT32_MAX;
+ sk_mutable->s_flags |= NL_OWN_PORT;
+ } else
+ sk_mutable->s_flags &= ~NL_OWN_PORT;
}
return sk->s_local.nl_pid;
}
@@ -434,6 +452,8 @@ int nl_socket_add_memberships(struct nl_sock *sk, int group, ...)
&group, sizeof(group));
if (err < 0) {
va_end(ap);
+ NL_DBG(4, "nl_socket_add_memberships(%p): setsockopt() failed with %d (%s)\n",
+ sk, errno, nl_strerror_l(errno));
return -nl_syserr2nlerr(errno);
}
@@ -482,6 +502,8 @@ int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...)
&group, sizeof(group));
if (err < 0) {
va_end(ap);
+ NL_DBG(4, "nl_socket_drop_memberships(%p): setsockopt() failed with %d (%s)\n",
+ sk, errno, nl_strerror_l(errno));
return -nl_syserr2nlerr(errno);
}
@@ -565,6 +587,114 @@ int nl_socket_get_fd(const struct nl_sock *sk)
}
/**
+ * Set the socket file descriptor externally which initializes the
+ * socket similar to nl_connect().
+ *
+ * @arg sk Netlink socket (required)
+ * @arg protocol The socket protocol (optional). Linux 2.6.32 supports
+ * the socket option SO_PROTOCOL. In this case, you can set
+ * protocol to a negative value and let it autodetect.
+ * If you set it to a non-negative value, the detected protocol
+ * must match the one provided.
+ * To support older kernels, you must specify the protocol.
+ * @arg fd Socket file descriptor to use (required)
+ *
+ * Set the socket file descriptor. @fd must be valid and bind'ed.
+ *
+ * This is an alternative to nl_connect(). nl_connect() creates, binds and
+ * sets the socket. With this function you can set the socket to an externally
+ * created file descriptor.
+ *
+ * @see nl_connect()
+ *
+ * @return 0 on success or a negative error code. On error, @fd is not closed but
+ * possibly unusable.
+ *
+ * @retval -NLE_BAD_SOCK Netlink socket is already connected
+ * @retval -NLE_INVAL Socket is of unexpected type
+ */
+int nl_socket_set_fd(struct nl_sock *sk, int protocol, int fd)
+{
+ int err = 0;
+ socklen_t addrlen;
+ struct sockaddr_nl local = { 0 };
+ int so_type = -1, so_protocol = -1;
+
+ if (sk->s_fd != -1)
+ return -NLE_BAD_SOCK;
+ if (fd < 0)
+ return -NLE_INVAL;
+
+ addrlen = sizeof(local);
+ err = getsockname(fd, (struct sockaddr *) &local,
+ &addrlen);
+ if (err < 0) {
+ NL_DBG(4, "nl_socket_set_fd(%p,%d): getsockname() failed with %d (%s)\n",
+ sk, fd, errno, nl_strerror_l(errno));
+ return -nl_syserr2nlerr(errno);
+ }
+ if (addrlen != sizeof(local))
+ return -NLE_INVAL;
+ if (local.nl_family != AF_NETLINK) {
+ NL_DBG(4, "nl_socket_set_fd(%p,%d): getsockname() returned family %d instead of %d (AF_NETLINK)\n",
+ sk, fd, local.nl_family, AF_NETLINK);
+ return -NLE_INVAL;
+ }
+
+ addrlen = sizeof(so_type);
+ err = getsockopt(fd, SOL_SOCKET, SO_TYPE, &so_type, &addrlen);
+ if (err < 0) {
+ NL_DBG(4, "nl_socket_set_fd(%p,%d): getsockopt() for SO_TYPE failed with %d (%s)\n",
+ sk, fd, errno, nl_strerror_l(errno));
+ return -nl_syserr2nlerr(errno);
+ }
+ if (addrlen != sizeof(so_type))
+ return -NLE_INVAL;
+ if (so_type != SOCK_RAW) {
+ NL_DBG(4, "nl_socket_set_fd(%p,%d): getsockopt() returned SO_TYPE %d instead of %d (SOCK_RAW)\n",
+ sk, fd, so_type, SOCK_RAW);
+ return -NLE_INVAL;
+ }
+
+#if SO_PROTOCOL
+ addrlen = sizeof(so_protocol);
+ err = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &so_protocol, &addrlen);
+ if (err < 0) {
+ if (errno == ENOPROTOOPT)
+ goto no_so_protocol;
+ NL_DBG(4, "nl_socket_set_fd(%p,%d): getsockopt() for SO_PROTOCOL failed with %d (%s)\n",
+ sk, fd, errno, nl_strerror_l(errno));
+ return -nl_syserr2nlerr(errno);
+ }
+ if (addrlen != sizeof(so_protocol))
+ return -NLE_INVAL;
+ if (protocol >= 0 && protocol != so_protocol) {
+ NL_DBG(4, "nl_socket_set_fd(%p,%d): getsockopt() for SO_PROTOCOL returned %d instead of %d\n",
+ sk, fd, so_protocol, protocol);
+ return -NLE_INVAL;
+ }
+
+ if (0)
+#endif
+ {
+no_so_protocol:
+ if (protocol < 0) {
+ NL_DBG(4, "nl_socket_set_fd(%p,%d): unknown protocol and unable to detect it via SO_PROTOCOL socket option\n",
+ sk, fd);
+ return -NLE_INVAL;
+ }
+ so_protocol = protocol;
+ }
+
+ nl_socket_set_local_port (sk, local.nl_pid);
+ sk->s_local = local;
+ sk->s_fd = fd;
+ sk->s_proto = so_protocol;
+
+ return 0;
+}
+
+/**
* Set file descriptor of socket to non-blocking state
* @arg sk Netlink socket.
*
@@ -575,8 +705,11 @@ int nl_socket_set_nonblocking(const struct nl_sock *sk)
if (sk->s_fd == -1)
return -NLE_BAD_SOCK;
- if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
+ if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0) {
+ NL_DBG(4, "nl_socket_set_nonblocking(%p): fcntl() failed with %d (%s)\n",
+ sk, errno, nl_strerror_l(errno));
return -nl_syserr2nlerr(errno);
+ }
return 0;
}
@@ -584,18 +717,23 @@ int nl_socket_set_nonblocking(const struct nl_sock *sk)
/**
* Enable use of MSG_PEEK when reading from socket
* @arg sk Netlink socket.
+ *
+ * See also NL_CAPABILITY_NL_RECVMSGS_PEEK_BY_DEFAULT capability
*/
void nl_socket_enable_msg_peek(struct nl_sock *sk)
{
- sk->s_flags |= NL_MSG_PEEK;
+ sk->s_flags |= (NL_MSG_PEEK | NL_MSG_PEEK_EXPLICIT);
}
/**
* Disable use of MSG_PEEK when reading from socket
* @arg sk Netlink socket.
+ *
+ * See also NL_CAPABILITY_NL_RECVMSGS_PEEK_BY_DEFAULT capability
*/
void nl_socket_disable_msg_peek(struct nl_sock *sk)
{
+ sk->s_flags |= NL_MSG_PEEK_EXPLICIT;
sk->s_flags &= ~NL_MSG_PEEK;
}
@@ -613,8 +751,8 @@ struct nl_cb *nl_socket_get_cb(const struct nl_sock *sk)
void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb)
{
- if (cb == NULL)
- BUG();
+ if (cb == NULL)
+ BUG();
nl_cb_put(sk->s_cb);
sk->s_cb = nl_cb_get(cb);
@@ -684,18 +822,22 @@ int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
if (sk->s_fd == -1)
return -NLE_BAD_SOCK;
-
+
err = setsockopt(sk->s_fd, SOL_SOCKET, SO_SNDBUF,
&txbuf, sizeof(txbuf));
- if (err < 0)
+ if (err < 0) {
+ NL_DBG(4, "nl_socket_set_buffer_size(%p): setsockopt() failed with %d (%s)\n",
+ sk, errno, nl_strerror_l(errno));
return -nl_syserr2nlerr(errno);
+ }
err = setsockopt(sk->s_fd, SOL_SOCKET, SO_RCVBUF,
&rxbuf, sizeof(rxbuf));
- if (err < 0)
+ if (err < 0) {
+ NL_DBG(4, "nl_socket_set_buffer_size(%p): setsockopt() failed with %d (%s)\n",
+ sk, errno, nl_strerror_l(errno));
return -nl_syserr2nlerr(errno);
-
- sk->s_flags |= NL_SOCK_BUFSIZE_SET;
+ }
return 0;
}
@@ -710,6 +852,19 @@ int nl_socket_set_buffer_size(struct nl_sock *sk, int rxbuf, int txbuf)
* socket will be able to receive. It is generally recommneded to specify
* a buffer size no less than the size of a memory page.
*
+ * Setting the @bufsize to zero means to use a default of 4 times getpagesize().
+ *
+ * When MSG_PEEK is enabled, the buffer size is used for the initial choice
+ * of the buffer while peeking. It still makes sense to choose an optimal value
+ * to avoid realloc().
+ *
+ * When MSG_PEEK is disabled, the buffer size is important because a too small
+ * size will lead to failure of receiving the message via nl_recvmsgs().
+ *
+ * By default, MSG_PEEK is enabled unless the user calls either nl_socket_disable_msg_peek()/
+ * nl_socket_enable_msg_peek() or sets the message buffer size to a positive value.
+ * See capability NL_CAPABILITY_NL_RECVMSGS_PEEK_BY_DEFAULT for that.
+ *
* @return 0 on success or a negative error code.
*/
int nl_socket_set_msg_buf_size(struct nl_sock *sk, size_t bufsize)
@@ -746,8 +901,11 @@ int nl_socket_set_passcred(struct nl_sock *sk, int state)
err = setsockopt(sk->s_fd, SOL_SOCKET, SO_PASSCRED,
&state, sizeof(state));
- if (err < 0)
+ if (err < 0) {
+ NL_DBG(4, "nl_socket_set_passcred(%p): setsockopt() failed with %d (%s)\n",
+ sk, errno, nl_strerror_l(errno));
return -nl_syserr2nlerr(errno);
+ }
if (state)
sk->s_flags |= NL_SOCK_PASSCRED;
@@ -773,8 +931,11 @@ int nl_socket_recv_pktinfo(struct nl_sock *sk, int state)
err = setsockopt(sk->s_fd, SOL_NETLINK, NETLINK_PKTINFO,
&state, sizeof(state));
- if (err < 0)
+ if (err < 0) {
+ NL_DBG(4, "nl_socket_recv_pktinfo(%p): setsockopt() failed with %d (%s)\n",
+ sk, errno, nl_strerror_l(errno));
return -nl_syserr2nlerr(errno);
+ }
return 0;
}
diff --git a/lib/utils.c b/lib/utils.c
index 7b44243c..496bf3b3 100644
--- a/lib/utils.c
+++ b/lib/utils.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/utils.c Utility Functions
*
@@ -25,10 +26,14 @@
*/
#include <netlink-private/netlink.h>
+#include <netlink-private/utils.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <linux/socket.h>
#include <stdlib.h> /* exit() */
+#ifdef HAVE_STRERROR_L
+#include <locale.h>
+#endif
/**
* Global variable indicating the desired level of debugging output.
@@ -57,7 +62,7 @@ struct nl_dump_params nl_debug_dp = {
static void __init nl_debug_init(void)
{
char *nldbg, *end;
-
+
if ((nldbg = getenv("NLDBG"))) {
long level = strtol(nldbg, &end, 0);
if (nldbg != end)
@@ -73,7 +78,7 @@ int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
FILE *fd;
char buf[128];
- fd = fopen(path, "r");
+ fd = fopen(path, "re");
if (fd == NULL)
return -nl_syserr2nlerr(errno);
@@ -118,6 +123,32 @@ int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *))
return 0;
}
+
+const char *nl_strerror_l(int err)
+{
+ const char *buf;
+#ifdef HAVE_STRERROR_L
+ int errno_save = errno;
+ locale_t loc = newlocale(LC_MESSAGES_MASK, "", (locale_t)0);
+
+ if (loc == (locale_t)0) {
+ if (errno == ENOENT)
+ loc = newlocale(LC_MESSAGES_MASK,
+ "POSIX", (locale_t)0);
+ }
+ if (loc != (locale_t)0) {
+ buf = strerror_l(err, loc);
+ freelocale(loc);
+ } else {
+ buf = "newlocale() failed";
+ }
+
+ errno = errno_save;
+#else
+ buf = strerror(err);
+#endif
+ return buf;
+}
/** @endcond */
/**
@@ -202,11 +233,11 @@ int nl_rate2str(unsigned long long rate, int type, char *buf, size_t len)
case NL_BYTE_RATE:
frac = nl_cancel_down_bytes(rate, &unit);
break;
-
+
case NL_BIT_RATE:
frac = nl_cancel_down_bits(rate, &unit);
break;
-
+
default:
BUG();
}
@@ -375,7 +406,7 @@ long nl_prob2int(const char *str)
if (*p && strcmp(p, "%") != 0)
return -NLE_INVAL;
- return rint(d * NL_PROB_MAX);
+ return (long) (((d * NL_PROB_MAX) + 0.5));
}
/** @} */
@@ -445,19 +476,19 @@ static void get_psched_settings(void)
snprintf(name, sizeof(name), "%s/net/psched", ev);
else
strncpy(name, "/proc/net/psched", sizeof(name) - 1);
-
- if ((fd = fopen(name, "r"))) {
+
+ if ((fd = fopen(name, "re"))) {
unsigned int ns_per_usec, ns_per_tick, nom, denom;
if (fscanf(fd, "%08x %08x %08x %08x",
&ns_per_usec, &ns_per_tick, &nom, &denom) != 4) {
- NL_DBG(1, "Fatal error: can not read psched settings from \"%s\". " \
- "Try to set TICKS_PER_USEC, PROC_NET_PSCHED or PROC_ROOT " \
- "environment variables\n", name);
- exit(1);
- }
+ NL_DBG(1, "Fatal error: can not read psched settings from \"%s\". " \
+ "Try to set TICKS_PER_USEC, PROC_NET_PSCHED or PROC_ROOT " \
+ "environment variables\n", name);
+ exit(1);
+ }
- ticks_per_usec = (double) ns_per_usec /
+ ticks_per_usec = (double) ns_per_usec /
(double) ns_per_tick;
if (nom == 1000000)
@@ -602,24 +633,26 @@ char * nl_msec2str(uint64_t msec, char *buf, size_t len)
*/
static const struct trans_tbl nlfamilies[] = {
- __ADD(NETLINK_ROUTE,route)
- __ADD(NETLINK_USERSOCK,usersock)
- __ADD(NETLINK_FIREWALL,firewall)
- __ADD(NETLINK_INET_DIAG,inetdiag)
- __ADD(NETLINK_NFLOG,nflog)
- __ADD(NETLINK_XFRM,xfrm)
- __ADD(NETLINK_SELINUX,selinux)
- __ADD(NETLINK_ISCSI,iscsi)
- __ADD(NETLINK_AUDIT,audit)
- __ADD(NETLINK_FIB_LOOKUP,fib_lookup)
- __ADD(NETLINK_CONNECTOR,connector)
- __ADD(NETLINK_NETFILTER,netfilter)
- __ADD(NETLINK_IP6_FW,ip6_fw)
- __ADD(NETLINK_DNRTMSG,dnrtmsg)
- __ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent)
- __ADD(NETLINK_GENERIC,generic)
- __ADD(NETLINK_SCSITRANSPORT,scsitransport)
- __ADD(NETLINK_ECRYPTFS,ecryptfs)
+ __ADD(NETLINK_ROUTE,route),
+ __ADD(NETLINK_USERSOCK,usersock),
+ __ADD(NETLINK_FIREWALL,firewall),
+ __ADD(NETLINK_INET_DIAG,inetdiag),
+ __ADD(NETLINK_NFLOG,nflog),
+ __ADD(NETLINK_XFRM,xfrm),
+ __ADD(NETLINK_SELINUX,selinux),
+ __ADD(NETLINK_ISCSI,iscsi),
+ __ADD(NETLINK_AUDIT,audit),
+ __ADD(NETLINK_FIB_LOOKUP,fib_lookup),
+ __ADD(NETLINK_CONNECTOR,connector),
+ __ADD(NETLINK_NETFILTER,netfilter),
+ __ADD(NETLINK_IP6_FW,ip6_fw),
+ __ADD(NETLINK_DNRTMSG,dnrtmsg),
+ __ADD(NETLINK_KOBJECT_UEVENT,kobject_uevent),
+ __ADD(NETLINK_GENERIC,generic),
+ __ADD(NETLINK_SCSITRANSPORT,scsitransport),
+ __ADD(NETLINK_ECRYPTFS,ecryptfs),
+ __ADD(NETLINK_RDMA,rdma),
+ __ADD(NETLINK_CRYPTO,crypto),
};
char * nl_nlfamily2str(int family, char *buf, size_t size)
@@ -644,86 +677,83 @@ int nl_str2nlfamily(const char *name)
static const struct trans_tbl llprotos[] = {
{0, "generic"},
- __ADD(ARPHRD_ETHER,ether)
- __ADD(ARPHRD_EETHER,eether)
- __ADD(ARPHRD_AX25,ax25)
- __ADD(ARPHRD_PRONET,pronet)
- __ADD(ARPHRD_CHAOS,chaos)
- __ADD(ARPHRD_IEEE802,ieee802)
- __ADD(ARPHRD_ARCNET,arcnet)
- __ADD(ARPHRD_APPLETLK,atalk)
- __ADD(ARPHRD_DLCI,dlci)
- __ADD(ARPHRD_ATM,atm)
- __ADD(ARPHRD_METRICOM,metricom)
- __ADD(ARPHRD_IEEE1394,ieee1394)
-#ifdef ARPHRD_EUI64
- __ADD(ARPHRD_EUI64,eui64)
-#endif
- __ADD(ARPHRD_INFINIBAND,infiniband)
- __ADD(ARPHRD_SLIP,slip)
- __ADD(ARPHRD_CSLIP,cslip)
- __ADD(ARPHRD_SLIP6,slip6)
- __ADD(ARPHRD_CSLIP6,cslip6)
- __ADD(ARPHRD_RSRVD,rsrvd)
- __ADD(ARPHRD_ADAPT,adapt)
- __ADD(ARPHRD_ROSE,rose)
- __ADD(ARPHRD_X25,x25)
-#ifdef ARPHRD_HWX25
- __ADD(ARPHRD_HWX25,hwx25)
-#endif
- __ADD(ARPHRD_CAN,can)
- __ADD(ARPHRD_PPP,ppp)
- __ADD(ARPHRD_HDLC,hdlc)
- __ADD(ARPHRD_LAPB,lapb)
- __ADD(ARPHRD_DDCMP,ddcmp)
- __ADD(ARPHRD_RAWHDLC,rawhdlc)
- __ADD(ARPHRD_TUNNEL,ipip)
- __ADD(ARPHRD_TUNNEL6,tunnel6)
- __ADD(ARPHRD_FRAD,frad)
- __ADD(ARPHRD_SKIP,skip)
- __ADD(ARPHRD_LOOPBACK,loopback)
- __ADD(ARPHRD_LOCALTLK,localtlk)
- __ADD(ARPHRD_FDDI,fddi)
- __ADD(ARPHRD_BIF,bif)
- __ADD(ARPHRD_SIT,sit)
- __ADD(ARPHRD_IPDDP,ip/ddp)
- __ADD(ARPHRD_IPGRE,gre)
- __ADD(ARPHRD_PIMREG,pimreg)
- __ADD(ARPHRD_HIPPI,hippi)
- __ADD(ARPHRD_ASH,ash)
- __ADD(ARPHRD_ECONET,econet)
- __ADD(ARPHRD_IRDA,irda)
- __ADD(ARPHRD_FCPP,fcpp)
- __ADD(ARPHRD_FCAL,fcal)
- __ADD(ARPHRD_FCPL,fcpl)
- __ADD(ARPHRD_FCFABRIC,fcfb_0)
- __ADD(ARPHRD_FCFABRIC+1,fcfb_1)
- __ADD(ARPHRD_FCFABRIC+2,fcfb_2)
- __ADD(ARPHRD_FCFABRIC+3,fcfb_3)
- __ADD(ARPHRD_FCFABRIC+4,fcfb_4)
- __ADD(ARPHRD_FCFABRIC+5,fcfb_5)
- __ADD(ARPHRD_FCFABRIC+6,fcfb_6)
- __ADD(ARPHRD_FCFABRIC+7,fcfb_7)
- __ADD(ARPHRD_FCFABRIC+8,fcfb_8)
- __ADD(ARPHRD_FCFABRIC+9,fcfb_9)
- __ADD(ARPHRD_FCFABRIC+10,fcfb_10)
- __ADD(ARPHRD_FCFABRIC+11,fcfb_11)
- __ADD(ARPHRD_FCFABRIC+12,fcfb_12)
- __ADD(ARPHRD_IEEE802_TR,tr)
- __ADD(ARPHRD_IEEE80211,ieee802.11)
- __ADD(ARPHRD_PHONET,phonet)
-#ifdef ARPHRD_CAIF
- __ADD(ARPHRD_CAIF, caif)
-#endif
-#ifdef ARPHRD_IEEE80211_PRISM
- __ADD(ARPHRD_IEEE80211_PRISM, ieee802.11_prism)
-#endif
-#ifdef ARPHRD_VOID
- __ADD(ARPHRD_VOID,void)
-#endif
-#ifdef ARPHRD_NONE
- __ADD(ARPHRD_NONE,nohdr)
-#endif
+ __ADD(ARPHRD_NETROM,netrom),
+ __ADD(ARPHRD_ETHER,ether),
+ __ADD(ARPHRD_EETHER,eether),
+ __ADD(ARPHRD_AX25,ax25),
+ __ADD(ARPHRD_PRONET,pronet),
+ __ADD(ARPHRD_CHAOS,chaos),
+ __ADD(ARPHRD_IEEE802,ieee802),
+ __ADD(ARPHRD_ARCNET,arcnet),
+ __ADD(ARPHRD_APPLETLK,atalk),
+ __ADD(ARPHRD_DLCI,dlci),
+ __ADD(ARPHRD_ATM,atm),
+ __ADD(ARPHRD_METRICOM,metricom),
+ __ADD(ARPHRD_IEEE1394,ieee1394),
+ __ADD(ARPHRD_EUI64,eui64),
+ __ADD(ARPHRD_INFINIBAND,infiniband),
+ __ADD(ARPHRD_SLIP,slip),
+ __ADD(ARPHRD_CSLIP,cslip),
+ __ADD(ARPHRD_SLIP6,slip6),
+ __ADD(ARPHRD_CSLIP6,cslip6),
+ __ADD(ARPHRD_RSRVD,rsrvd),
+ __ADD(ARPHRD_ADAPT,adapt),
+ __ADD(ARPHRD_ROSE,rose),
+ __ADD(ARPHRD_X25,x25),
+ __ADD(ARPHRD_HWX25,hwx25),
+ __ADD(ARPHRD_CAN,can),
+ __ADD(ARPHRD_PPP,ppp),
+ __ADD(ARPHRD_CISCO,cisco),
+ __ADD(ARPHRD_HDLC,hdlc),
+ __ADD(ARPHRD_LAPB,lapb),
+ __ADD(ARPHRD_DDCMP,ddcmp),
+ __ADD(ARPHRD_RAWHDLC,rawhdlc),
+ __ADD(ARPHRD_TUNNEL,ipip),
+ __ADD(ARPHRD_TUNNEL6,tunnel6),
+ __ADD(ARPHRD_FRAD,frad),
+ __ADD(ARPHRD_SKIP,skip),
+ __ADD(ARPHRD_LOOPBACK,loopback),
+ __ADD(ARPHRD_LOCALTLK,localtlk),
+ __ADD(ARPHRD_FDDI,fddi),
+ __ADD(ARPHRD_BIF,bif),
+ __ADD(ARPHRD_SIT,sit),
+ __ADD(ARPHRD_IPDDP,ip/ddp),
+ __ADD(ARPHRD_IPGRE,gre),
+ __ADD(ARPHRD_PIMREG,pimreg),
+ __ADD(ARPHRD_HIPPI,hippi),
+ __ADD(ARPHRD_ASH,ash),
+ __ADD(ARPHRD_ECONET,econet),
+ __ADD(ARPHRD_IRDA,irda),
+ __ADD(ARPHRD_FCPP,fcpp),
+ __ADD(ARPHRD_FCAL,fcal),
+ __ADD(ARPHRD_FCPL,fcpl),
+ __ADD(ARPHRD_FCFABRIC,fcfb_0),
+ __ADD(ARPHRD_FCFABRIC+1,fcfb_1),
+ __ADD(ARPHRD_FCFABRIC+2,fcfb_2),
+ __ADD(ARPHRD_FCFABRIC+3,fcfb_3),
+ __ADD(ARPHRD_FCFABRIC+4,fcfb_4),
+ __ADD(ARPHRD_FCFABRIC+5,fcfb_5),
+ __ADD(ARPHRD_FCFABRIC+6,fcfb_6),
+ __ADD(ARPHRD_FCFABRIC+7,fcfb_7),
+ __ADD(ARPHRD_FCFABRIC+8,fcfb_8),
+ __ADD(ARPHRD_FCFABRIC+9,fcfb_9),
+ __ADD(ARPHRD_FCFABRIC+10,fcfb_10),
+ __ADD(ARPHRD_FCFABRIC+11,fcfb_11),
+ __ADD(ARPHRD_FCFABRIC+12,fcfb_12),
+ __ADD(ARPHRD_IEEE802_TR,tr),
+ __ADD(ARPHRD_IEEE80211,ieee802.11),
+ __ADD(ARPHRD_IEEE80211_PRISM,ieee802.11_prism),
+ __ADD(ARPHRD_IEEE80211_RADIOTAP,ieee802.11_radiotap),
+ __ADD(ARPHRD_IEEE802154,ieee802.15.4),
+ __ADD(ARPHRD_IEEE802154_MONITOR,ieee802.15.4_monitor),
+ __ADD(ARPHRD_PHONET,phonet),
+ __ADD(ARPHRD_PHONET_PIPE,phonet_pipe),
+ __ADD(ARPHRD_CAIF,caif),
+ __ADD(ARPHRD_IP6GRE,ip6gre),
+ __ADD(ARPHRD_NETLINK,netlink),
+ __ADD(ARPHRD_6LOWPAN,6lowpan),
+ __ADD(ARPHRD_VOID,void),
+ __ADD(ARPHRD_NONE,nohdr),
};
char * nl_llproto2str(int llproto, char *buf, size_t len)
@@ -745,75 +775,75 @@ int nl_str2llproto(const char *name)
*/
static const struct trans_tbl ether_protos[] = {
- __ADD(ETH_P_LOOP,loop)
- __ADD(ETH_P_PUP,pup)
- __ADD(ETH_P_PUPAT,pupat)
- __ADD(ETH_P_IP,ip)
- __ADD(ETH_P_X25,x25)
- __ADD(ETH_P_ARP,arp)
- __ADD(ETH_P_BPQ,bpq)
- __ADD(ETH_P_IEEEPUP,ieeepup)
- __ADD(ETH_P_IEEEPUPAT,ieeepupat)
- __ADD(ETH_P_DEC,dec)
- __ADD(ETH_P_DNA_DL,dna_dl)
- __ADD(ETH_P_DNA_RC,dna_rc)
- __ADD(ETH_P_DNA_RT,dna_rt)
- __ADD(ETH_P_LAT,lat)
- __ADD(ETH_P_DIAG,diag)
- __ADD(ETH_P_CUST,cust)
- __ADD(ETH_P_SCA,sca)
- __ADD(ETH_P_TEB,teb)
- __ADD(ETH_P_RARP,rarp)
- __ADD(ETH_P_ATALK,atalk)
- __ADD(ETH_P_AARP,aarp)
+ __ADD(ETH_P_LOOP,loop),
+ __ADD(ETH_P_PUP,pup),
+ __ADD(ETH_P_PUPAT,pupat),
+ __ADD(ETH_P_IP,ip),
+ __ADD(ETH_P_X25,x25),
+ __ADD(ETH_P_ARP,arp),
+ __ADD(ETH_P_BPQ,bpq),
+ __ADD(ETH_P_IEEEPUP,ieeepup),
+ __ADD(ETH_P_IEEEPUPAT,ieeepupat),
+ __ADD(ETH_P_DEC,dec),
+ __ADD(ETH_P_DNA_DL,dna_dl),
+ __ADD(ETH_P_DNA_RC,dna_rc),
+ __ADD(ETH_P_DNA_RT,dna_rt),
+ __ADD(ETH_P_LAT,lat),
+ __ADD(ETH_P_DIAG,diag),
+ __ADD(ETH_P_CUST,cust),
+ __ADD(ETH_P_SCA,sca),
+ __ADD(ETH_P_TEB,teb),
+ __ADD(ETH_P_RARP,rarp),
+ __ADD(ETH_P_ATALK,atalk),
+ __ADD(ETH_P_AARP,aarp),
#ifdef ETH_P_8021Q
- __ADD(ETH_P_8021Q,802.1q)
+ __ADD(ETH_P_8021Q,802.1q),
#endif
- __ADD(ETH_P_IPX,ipx)
- __ADD(ETH_P_IPV6,ipv6)
- __ADD(ETH_P_PAUSE,pause)
- __ADD(ETH_P_SLOW,slow)
+ __ADD(ETH_P_IPX,ipx),
+ __ADD(ETH_P_IPV6,ipv6),
+ __ADD(ETH_P_PAUSE,pause),
+ __ADD(ETH_P_SLOW,slow),
#ifdef ETH_P_WCCP
- __ADD(ETH_P_WCCP,wccp)
+ __ADD(ETH_P_WCCP,wccp),
#endif
- __ADD(ETH_P_PPP_DISC,ppp_disc)
- __ADD(ETH_P_PPP_SES,ppp_ses)
- __ADD(ETH_P_MPLS_UC,mpls_uc)
- __ADD(ETH_P_MPLS_MC,mpls_mc)
- __ADD(ETH_P_ATMMPOA,atmmpoa)
- __ADD(ETH_P_LINK_CTL,link_ctl)
- __ADD(ETH_P_ATMFATE,atmfate)
- __ADD(ETH_P_PAE,pae)
- __ADD(ETH_P_AOE,aoe)
- __ADD(ETH_P_TIPC,tipc)
- __ADD(ETH_P_1588,ieee1588)
- __ADD(ETH_P_FCOE,fcoe)
- __ADD(ETH_P_FIP,fip)
- __ADD(ETH_P_EDSA,edsa)
- __ADD(ETH_P_EDP2,edp2)
- __ADD(ETH_P_802_3,802.3)
- __ADD(ETH_P_AX25,ax25)
- __ADD(ETH_P_ALL,all)
- __ADD(ETH_P_802_2,802.2)
- __ADD(ETH_P_SNAP,snap)
- __ADD(ETH_P_DDCMP,ddcmp)
- __ADD(ETH_P_WAN_PPP,wan_ppp)
- __ADD(ETH_P_PPP_MP,ppp_mp)
- __ADD(ETH_P_LOCALTALK,localtalk)
- __ADD(ETH_P_CAN,can)
- __ADD(ETH_P_PPPTALK,ppptalk)
- __ADD(ETH_P_TR_802_2,tr_802.2)
- __ADD(ETH_P_MOBITEX,mobitex)
- __ADD(ETH_P_CONTROL,control)
- __ADD(ETH_P_IRDA,irda)
- __ADD(ETH_P_ECONET,econet)
- __ADD(ETH_P_HDLC,hdlc)
- __ADD(ETH_P_ARCNET,arcnet)
- __ADD(ETH_P_DSA,dsa)
- __ADD(ETH_P_TRAILER,trailer)
- __ADD(ETH_P_PHONET,phonet)
- __ADD(ETH_P_IEEE802154,ieee802154)
- __ADD(ETH_P_CAIF,caif)
+ __ADD(ETH_P_PPP_DISC,ppp_disc),
+ __ADD(ETH_P_PPP_SES,ppp_ses),
+ __ADD(ETH_P_MPLS_UC,mpls_uc),
+ __ADD(ETH_P_MPLS_MC,mpls_mc),
+ __ADD(ETH_P_ATMMPOA,atmmpoa),
+ __ADD(ETH_P_LINK_CTL,link_ctl),
+ __ADD(ETH_P_ATMFATE,atmfate),
+ __ADD(ETH_P_PAE,pae),
+ __ADD(ETH_P_AOE,aoe),
+ __ADD(ETH_P_TIPC,tipc),
+ __ADD(ETH_P_1588,ieee1588),
+ __ADD(ETH_P_FCOE,fcoe),
+ __ADD(ETH_P_FIP,fip),
+ __ADD(ETH_P_EDSA,edsa),
+ __ADD(ETH_P_EDP2,edp2),
+ __ADD(ETH_P_802_3,802.3),
+ __ADD(ETH_P_AX25,ax25),
+ __ADD(ETH_P_ALL,all),
+ __ADD(ETH_P_802_2,802.2),
+ __ADD(ETH_P_SNAP,snap),
+ __ADD(ETH_P_DDCMP,ddcmp),
+ __ADD(ETH_P_WAN_PPP,wan_ppp),
+ __ADD(ETH_P_PPP_MP,ppp_mp),
+ __ADD(ETH_P_LOCALTALK,localtalk),
+ __ADD(ETH_P_CAN,can),
+ __ADD(ETH_P_PPPTALK,ppptalk),
+ __ADD(ETH_P_TR_802_2,tr_802.2),
+ __ADD(ETH_P_MOBITEX,mobitex),
+ __ADD(ETH_P_CONTROL,control),
+ __ADD(ETH_P_IRDA,irda),
+ __ADD(ETH_P_ECONET,econet),
+ __ADD(ETH_P_HDLC,hdlc),
+ __ADD(ETH_P_ARCNET,arcnet),
+ __ADD(ETH_P_DSA,dsa),
+ __ADD(ETH_P_TRAILER,trailer),
+ __ADD(ETH_P_PHONET,phonet),
+ __ADD(ETH_P_IEEE802154,ieee802154),
+ __ADD(ETH_P_CAIF,caif),
};
char *nl_ether_proto2str(int eproto, char *buf, size_t len)
@@ -1084,7 +1114,7 @@ int __str2flags(const char *buf, const struct trans_tbl *tbl, size_t tbl_len)
for (;;) {
if (*p == ' ')
p++;
-
+
t = strchr(p, ',');
len = t ? t - p : strlen(p);
for (i = 0; i < tbl_len; i++)
@@ -1165,10 +1195,51 @@ int nl_has_capability (int capability)
NL_CAPABILITY_ROUTE_LINK_VETH_GET_PEER_OWN_REFERENCE,
NL_CAPABILITY_ROUTE_LINK_CLS_ADD_ACT_OWN_REFERENCE,
NL_CAPABILITY_NL_CONNECT_RETRY_GENERATE_PORT_ON_ADDRINUSE,
- 0,
- 0,
+ NL_CAPABILITY_ROUTE_LINK_GET_KERNEL_FAIL_OPNOTSUPP,
+ NL_CAPABILITY_ROUTE_ADDR_COMPARE_CACHEINFO,
+ NL_CAPABILITY_VERSION_3_2_26,
+ NL_CAPABILITY_NL_RECV_FAIL_TRUNC_NO_PEEK),
+ _NL_SET(1,
+ NL_CAPABILITY_LINK_BUILD_CHANGE_REQUEST_SET_CHANGE,
+ NL_CAPABILITY_RTNL_NEIGH_GET_FILTER_AF_UNSPEC_FIX,
+ NL_CAPABILITY_VERSION_3_2_27,
+ NL_CAPABILITY_RTNL_LINK_VLAN_PROTOCOL_SERIALZE,
+ NL_CAPABILITY_RTNL_LINK_PARSE_GRE_REMOTE,
+ NL_CAPABILITY_RTNL_LINK_VLAN_INGRESS_MAP_CLEAR,
+ NL_CAPABILITY_RTNL_LINK_VXLAN_IO_COMPARE,
+ NL_CAPABILITY_NL_OBJECT_DIFF64),
+ _NL_SET (2,
+ NL_CAPABILITY_XFRM_SA_KEY_SIZE,
+ NL_CAPABILITY_RTNL_ADDR_PEER_FIX,
+ NL_CAPABILITY_VERSION_3_2_28,
+ NL_CAPABILITY_RTNL_ADDR_PEER_ID_FIX,
+ NL_CAPABILITY_NL_ADDR_FILL_SOCKADDR,
+ NL_CAPABILITY_XFRM_SEC_CTX_LEN,
+ NL_CAPABILITY_LINK_BUILD_ADD_REQUEST_SET_CHANGE,
+ NL_CAPABILITY_NL_RECVMSGS_PEEK_BY_DEFAULT),
+ _NL_SET (3,
+ NL_CAPABILITY_VERSION_3_2_29,
+ NL_CAPABILITY_XFRM_SP_SEC_CTX_LEN,
+ NL_CAPABILITY_VERSION_3_3_0,
+ NL_CAPABILITY_VERSION_3_4_0,
+ NL_CAPABILITY_ROUTE_FIX_VLAN_SET_EGRESS_MAP,
+ NL_CAPABILITY_VERSION_3_5_0,
0,
0),
+ /* IMPORTANT: these capability numbers are intended to be universal and stable
+ * for libnl3. Don't allocate new numbers on your own that differ from upstream
+ * libnl3.
+ *
+ * Instead register a capability number upstream too. We will take patches
+ * for that. We especially take patches to register a capability number that is
+ * only implemented in your fork of libnl3.
+ *
+ * If you really don't want that, use capabilities in the range 0x7000 to 0x7FFF.
+ * (NL_CAPABILITY_IS_USER_RESERVED). Upstream libnl3 will not register conflicting
+ * capabilities in that range.
+ *
+ * Obviously, only backport capability numbers to libnl versions that actually
+ * implement that capability as well. */
#undef _NL_SET
#undef _NL_SETV
#undef _NL_ASSERT
diff --git a/lib/version.c b/lib/version.c
index 0dcafa0f..4faae1c3 100644
--- a/lib/version.c
+++ b/lib/version.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* lib/version.c Run-time version information
*
diff --git a/lib/xfrm/ae.c b/lib/xfrm/ae.c
new file mode 100644
index 00000000..c7baf35d
--- /dev/null
+++ b/lib/xfrm/ae.c
@@ -0,0 +1,985 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**
+ * @ingroup xfrmnl
+ * @defgroup ae Attribute Element
+ * @brief
+ *
+ * The AE interface allows a user to retrieve and update various
+ * Security Association (SA) attributes such as lifetime, replay state etc.
+ *
+ * @par AE Flags
+ * @code
+ * XFRM_AE_UNSPEC
+ * XFRM_AE_RTHR=1
+ * XFRM_AE_RVAL=2
+ * XFRM_AE_LVAL=4
+ * XFRM_AE_ETHR=8
+ * XFRM_AE_CR=16
+ * XFRM_AE_CE=32
+ * XFRM_AE_CU=64
+ * @endcode
+ *
+ * @par AE Identification
+ * An AE is uniquely identified by the attributes listed below, whenever
+ * you refer to an existing AE all of the attributes must be set. There is
+ * no cache support for AE since you can retrieve the AE for any given combination
+ * of attributes mentioned below, but not all at once since they just characterize
+ * an SA.
+ * - destination address (xfrmnl_ae_set_daddr())
+ * - SPI (xfrmnl_ae_set_spi)
+ * - protocol (xfrmnl_ae_set_proto)
+ * - mark (xfrmnl_ae_set_mark)
+ *
+ * @par Changeable Attributes
+ * \anchor ae_changeable
+ * - current lifetime (xfrmnl_ae_set_curlifetime())
+ * - replay properties (xfrmnl_ae_set_replay_maxage(), xfrmnl_ae_set_replay_maxdiff())
+ * - replay state (xfrmnl_ae_set_replay_state(), xfrmnl_ae_set_replay_state_esn))
+ *
+ * @par Required Caches for Dumping
+ * None
+ *
+ * @par TODO
+ * None
+ *
+ * @par 1) Retrieving AE information for a given SA tuple
+ * @code
+ * // Create a netlink socket and connect it to XFRM subsystem in
+ * the kernel to be able to send/receive info from userspace.
+ * struct nl_sock* sk = nl_socket_alloc ();
+ * nl_connect (sk, NETLINK_XFRM);
+ *
+ * // AEs can then be looked up by the SA tuple, destination address,
+ * SPI, protocol, mark:
+ * struct xfrmnl_ae *ae;
+ * xfrmnl_ae_get_kernel(sk, dst_addr, spi, proto,mark_mask, mark_value, &ae);
+ *
+ * // After successful usage, the object must be freed
+ * xfrmnl_ae_put(ae);
+ * @endcode
+ *
+ * @par 2) Updating AE
+ * @code
+ * // Allocate an empty AE handle to be filled out with the attributes
+ * // of the new AE.
+ * struct xfrmnl_ae *ae = xfrmnl_ae_alloc();
+ *
+ * // Fill out the attributes of the new AE
+ * xfrmnl_ae_set_daddr(ae, dst_addr);
+ * xfrmnl_ae_set_spi(ae, 0xDEADBEEF);
+ * xfrmnl_ae_set_proto(ae, 50);
+ * xfrmnl_ae_set_mark(ae, 0x0);
+ * xfrmnl_ae_set_saddr(ae, src_addr);
+ * xfrmnl_ae_set_curlifetime(ae, 540, 10, 0xAABB1122, 0x0);
+ *
+ * // Build the netlink message and send it to the kernel, the operation will
+ * // block until the operation has been completed. Alternatively, a netlink message
+ * // can be built using xfrmnl_ae_build_get_request () API and be sent using
+ * // nl_send_auto(). Further the result from the kernel can be parsed using
+ * // xfrmnl_ae_parse() API.
+ * xfrmnl_ae_set(sk, ae, NLM_F_REPLACE);
+ *
+ * // Free the memory
+ * xfrmnl_ae_put(ae);
+ * @endcode
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/object.h>
+#include <netlink/xfrm/ae.h>
+#include <linux/xfrm.h>
+
+/** @cond SKIP */
+#define XFRM_AE_ATTR_DADDR 0x01
+#define XFRM_AE_ATTR_SPI 0x02
+#define XFRM_AE_ATTR_PROTO 0x04
+#define XFRM_AE_ATTR_SADDR 0x08
+#define XFRM_AE_ATTR_FLAGS 0x10
+#define XFRM_AE_ATTR_REQID 0x20
+#define XFRM_AE_ATTR_MARK 0x40
+#define XFRM_AE_ATTR_LIFETIME 0x80
+#define XFRM_AE_ATTR_REPLAY_MAXAGE 0x100
+#define XFRM_AE_ATTR_REPLAY_MAXDIFF 0x200
+#define XFRM_AE_ATTR_REPLAY_STATE 0x400
+#define XFRM_AE_ATTR_FAMILY 0x800
+
+static struct nl_object_ops xfrm_ae_obj_ops;
+/** @endcond */
+
+
+static void xfrm_ae_free_data(struct nl_object *c)
+{
+ struct xfrmnl_ae* ae = nl_object_priv (c);
+
+ if (ae == NULL)
+ return;
+
+ nl_addr_put (ae->sa_id.daddr);
+ nl_addr_put (ae->saddr);
+
+ if (ae->replay_state_esn)
+ free (ae->replay_state_esn);
+}
+
+static int xfrm_ae_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+ struct xfrmnl_ae* dst = nl_object_priv(_dst);
+ struct xfrmnl_ae* src = nl_object_priv(_src);
+
+ if (src->sa_id.daddr)
+ if ((dst->sa_id.daddr = nl_addr_clone (src->sa_id.daddr)) == NULL)
+ return -NLE_NOMEM;
+
+ if (src->saddr)
+ if ((dst->saddr = nl_addr_clone (src->saddr)) == NULL)
+ return -NLE_NOMEM;
+
+ if (src->replay_state_esn)
+ {
+ uint32_t len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * src->replay_state_esn->bmp_len);
+ if ((dst->replay_state_esn = malloc (len)) == NULL)
+ return -NLE_NOMEM;
+ memcpy (dst->replay_state_esn, src->replay_state_esn, len);
+ }
+
+ return 0;
+}
+
+static uint64_t xfrm_ae_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
+{
+ struct xfrmnl_ae* a = (struct xfrmnl_ae *) _a;
+ struct xfrmnl_ae* b = (struct xfrmnl_ae *) _b;
+ uint64_t diff = 0;
+ int found = 0;
+
+#define XFRM_AE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, XFRM_AE_ATTR_##ATTR, a, b, EXPR)
+ diff |= XFRM_AE_DIFF(DADDR, nl_addr_cmp(a->sa_id.daddr, b->sa_id.daddr));
+ diff |= XFRM_AE_DIFF(SPI, a->sa_id.spi != b->sa_id.spi);
+ diff |= XFRM_AE_DIFF(PROTO, a->sa_id.proto != b->sa_id.proto);
+ diff |= XFRM_AE_DIFF(SADDR, nl_addr_cmp(a->saddr, b->saddr));
+ diff |= XFRM_AE_DIFF(FLAGS, a->flags != b->flags);
+ diff |= XFRM_AE_DIFF(REQID, a->reqid != b->reqid);
+ diff |= XFRM_AE_DIFF(MARK, (a->mark.v & a->mark.m) != (b->mark.v & b->mark.m));
+ diff |= XFRM_AE_DIFF(REPLAY_MAXAGE, a->replay_maxage != b->replay_maxage);
+ diff |= XFRM_AE_DIFF(REPLAY_MAXDIFF, a->replay_maxdiff != b->replay_maxdiff);
+
+ /* Compare replay states */
+ found = AVAILABLE_MISMATCH (a, b, XFRM_AE_ATTR_REPLAY_STATE);
+ if (found == 0) // attribute exists in both objects
+ {
+ if (((a->replay_state_esn != NULL) && (b->replay_state_esn == NULL)) ||
+ ((a->replay_state_esn == NULL) && (b->replay_state_esn != NULL)))
+ found |= 1;
+
+ if (found == 0) // same replay type. compare actual values
+ {
+ if (a->replay_state_esn)
+ {
+ if (a->replay_state_esn->bmp_len != b->replay_state_esn->bmp_len)
+ diff |= 1;
+ else
+ {
+ uint32_t len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * a->replay_state_esn->bmp_len);
+ diff |= memcmp (a->replay_state_esn, b->replay_state_esn, len);
+ }
+ }
+ else
+ {
+ if ((a->replay_state.oseq != b->replay_state.oseq) ||
+ (a->replay_state.seq != b->replay_state.seq) ||
+ (a->replay_state.bitmap != b->replay_state.bitmap))
+ diff |= 1;
+ }
+ }
+ }
+#undef XFRM_AE_DIFF
+
+ return diff;
+}
+
+/**
+ * @name XFRM AE Attribute Translations
+ * @{
+ */
+static const struct trans_tbl ae_attrs[] =
+{
+ __ADD(XFRM_AE_ATTR_DADDR, daddr),
+ __ADD(XFRM_AE_ATTR_SPI, spi),
+ __ADD(XFRM_AE_ATTR_PROTO, protocol),
+ __ADD(XFRM_AE_ATTR_SADDR, saddr),
+ __ADD(XFRM_AE_ATTR_FLAGS, flags),
+ __ADD(XFRM_AE_ATTR_REQID, reqid),
+ __ADD(XFRM_AE_ATTR_MARK, mark),
+ __ADD(XFRM_AE_ATTR_LIFETIME, cur_lifetime),
+ __ADD(XFRM_AE_ATTR_REPLAY_MAXAGE, replay_maxage),
+ __ADD(XFRM_AE_ATTR_REPLAY_MAXDIFF, replay_maxdiff),
+ __ADD(XFRM_AE_ATTR_REPLAY_STATE, replay_state),
+};
+
+static char* xfrm_ae_attrs2str (int attrs, char *buf, size_t len)
+{
+ return __flags2str(attrs, buf, len, ae_attrs, ARRAY_SIZE(ae_attrs));
+}
+/** @} */
+
+/**
+ * @name XFRM AE Flags Translations
+ * @{
+ */
+
+static const struct trans_tbl ae_flags[] = {
+ __ADD(XFRM_AE_UNSPEC, unspecified),
+ __ADD(XFRM_AE_RTHR, replay threshold),
+ __ADD(XFRM_AE_RVAL, replay value),
+ __ADD(XFRM_AE_LVAL, lifetime value),
+ __ADD(XFRM_AE_ETHR, expiry time threshold),
+ __ADD(XFRM_AE_CR, replay update event),
+ __ADD(XFRM_AE_CE, timer expiry event),
+ __ADD(XFRM_AE_CU, policy update event),
+};
+
+char* xfrmnl_ae_flags2str(int flags, char *buf, size_t len)
+{
+ return __flags2str (flags, buf, len, ae_flags, ARRAY_SIZE(ae_flags));
+}
+
+int xfrmnl_ae_str2flag(const char *name)
+{
+ return __str2flags(name, ae_flags, ARRAY_SIZE(ae_flags));
+}
+/** @} */
+
+static void xfrm_ae_dump_line(struct nl_object *a, struct nl_dump_params *p)
+{
+ char dst[INET6_ADDRSTRLEN+5], src[INET6_ADDRSTRLEN+5];
+ struct xfrmnl_ae* ae = (struct xfrmnl_ae *) a;
+ char flags[128], buf[128];
+ time_t add_time, use_time;
+ struct tm *add_time_tm, *use_time_tm;
+
+ nl_dump_line(p, "src %s dst %s \n", nl_addr2str(ae->saddr, src, sizeof(src)),
+ nl_addr2str(ae->sa_id.daddr, dst, sizeof(dst)));
+
+ nl_dump_line(p, "\tproto %s spi 0x%x reqid %u ",
+ nl_ip_proto2str (ae->sa_id.proto, buf, sizeof (buf)),
+ ae->sa_id.spi, ae->reqid);
+
+ xfrmnl_ae_flags2str(ae->flags, flags, sizeof (flags));
+ nl_dump_line(p, "flags %s(0x%x) mark mask/value 0x%x/0x%x \n", flags,
+ ae->flags, ae->mark.m, ae->mark.v);
+
+ nl_dump_line(p, "\tlifetime current: \n");
+ nl_dump_line(p, "\t\tbytes %llu packets %llu \n", ae->lifetime_cur.bytes,
+ ae->lifetime_cur.packets);
+ if (ae->lifetime_cur.add_time != 0)
+ {
+ add_time = ae->lifetime_cur.add_time;
+ add_time_tm = gmtime (&add_time);
+ strftime (flags, 128, "%Y-%m-%d %H-%M-%S", add_time_tm);
+ }
+ else
+ {
+ sprintf (flags, "%s", "-");
+ }
+
+ if (ae->lifetime_cur.use_time != 0)
+ {
+ use_time = ae->lifetime_cur.use_time;
+ use_time_tm = gmtime (&use_time);
+ strftime (buf, 128, "%Y-%m-%d %H-%M-%S", use_time_tm);
+ }
+ else
+ {
+ sprintf (buf, "%s", "-");
+ }
+ nl_dump_line(p, "\t\tadd_time: %s, use_time: %s\n", flags, buf);
+
+ nl_dump_line(p, "\treplay info: \n");
+ nl_dump_line(p, "\t\tmax age %u max diff %u \n", ae->replay_maxage, ae->replay_maxdiff);
+
+ nl_dump_line(p, "\treplay state info: \n");
+ if (ae->replay_state_esn)
+ {
+ nl_dump_line(p, "\t\toseq %u seq %u oseq_hi %u seq_hi %u replay window: %u \n",
+ ae->replay_state_esn->oseq, ae->replay_state_esn->seq,
+ ae->replay_state_esn->oseq_hi, ae->replay_state_esn->seq_hi,
+ ae->replay_state_esn->replay_window);
+ }
+ else
+ {
+ nl_dump_line(p, "\t\toseq %u seq %u bitmap: %u \n", ae->replay_state.oseq,
+ ae->replay_state.seq, ae->replay_state.bitmap);
+ }
+
+ nl_dump(p, "\n");
+}
+
+static void xfrm_ae_dump_details(struct nl_object *a, struct nl_dump_params *p)
+{
+ xfrm_ae_dump_line(a, p);
+}
+
+static void xfrm_ae_dump_stats(struct nl_object *a, struct nl_dump_params *p)
+{
+ xfrm_ae_dump_details(a, p);
+}
+
+
+static int build_xfrm_ae_message(struct xfrmnl_ae *tmpl, int cmd, int flags,
+ struct nl_msg **result)
+{
+ struct nl_msg* msg;
+ struct xfrm_aevent_id ae_id;
+
+ if (!(tmpl->ce_mask & XFRM_AE_ATTR_DADDR) ||
+ !(tmpl->ce_mask & XFRM_AE_ATTR_SPI) ||
+ !(tmpl->ce_mask & XFRM_AE_ATTR_PROTO))
+ return -NLE_MISSING_ATTR;
+
+ memcpy (&ae_id.sa_id.daddr, nl_addr_get_binary_addr (tmpl->sa_id.daddr), sizeof (uint8_t) * nl_addr_get_len (tmpl->sa_id.daddr));
+ ae_id.sa_id.spi = htonl(tmpl->sa_id.spi);
+ ae_id.sa_id.family = tmpl->sa_id.family;
+ ae_id.sa_id.proto = tmpl->sa_id.proto;
+
+ if (tmpl->ce_mask & XFRM_AE_ATTR_SADDR)
+ memcpy (&ae_id.saddr, nl_addr_get_binary_addr (tmpl->saddr), sizeof (uint8_t) * nl_addr_get_len (tmpl->saddr));
+
+ if (tmpl->ce_mask & XFRM_AE_ATTR_FLAGS)
+ ae_id.flags = tmpl->flags;
+
+ if (tmpl->ce_mask & XFRM_AE_ATTR_REQID)
+ ae_id.reqid = tmpl->reqid;
+
+ msg = nlmsg_alloc_simple(cmd, flags);
+ if (!msg)
+ return -NLE_NOMEM;
+
+ if (nlmsg_append(msg, &ae_id, sizeof(ae_id), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ if (tmpl->ce_mask & XFRM_AE_ATTR_MARK)
+ NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrmnl_mark), &tmpl->mark);
+
+ if (tmpl->ce_mask & XFRM_AE_ATTR_LIFETIME)
+ NLA_PUT (msg, XFRMA_LTIME_VAL, sizeof (struct xfrmnl_lifetime_cur), &tmpl->lifetime_cur);
+
+ if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_MAXAGE)
+ NLA_PUT_U32 (msg, XFRMA_ETIMER_THRESH, tmpl->replay_maxage);
+
+ if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_MAXDIFF)
+ NLA_PUT_U32 (msg, XFRMA_REPLAY_THRESH, tmpl->replay_maxdiff);
+
+ if (tmpl->ce_mask & XFRM_AE_ATTR_REPLAY_STATE) {
+ if (tmpl->replay_state_esn) {
+ uint32_t len = sizeof (struct xfrm_replay_state_esn) + (sizeof (uint32_t) * tmpl->replay_state_esn->bmp_len);
+ NLA_PUT (msg, XFRMA_REPLAY_ESN_VAL, len, tmpl->replay_state_esn);
+ }
+ else {
+ NLA_PUT (msg, XFRMA_REPLAY_VAL, sizeof (struct xfrmnl_replay_state), &tmpl->replay_state);
+ }
+ }
+
+ *result = msg;
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+}
+
+/**
+ * @name XFRM AE Update
+ * @{
+ */
+
+int xfrmnl_ae_set(struct nl_sock* sk, struct xfrmnl_ae* ae, int flags)
+{
+ int err;
+ struct nl_msg *msg;
+
+ if ((err = build_xfrm_ae_message(ae, XFRM_MSG_NEWAE, flags|NLM_F_REPLACE, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ return nl_wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * @name XFRM AE Object Allocation/Freeage
+ * @{
+ */
+
+struct xfrmnl_ae* xfrmnl_ae_alloc(void)
+{
+ return (struct xfrmnl_ae*) nl_object_alloc(&xfrm_ae_obj_ops);
+}
+
+void xfrmnl_ae_put(struct xfrmnl_ae* ae)
+{
+ nl_object_put((struct nl_object *) ae);
+}
+
+/** @} */
+
+static struct nla_policy xfrm_ae_policy[XFRMA_MAX+1] = {
+ [XFRMA_LTIME_VAL] = { .minlen = sizeof(struct xfrm_lifetime_cur) },
+ [XFRMA_REPLAY_VAL] = { .minlen = sizeof(struct xfrm_replay_state) },
+ [XFRMA_REPLAY_THRESH] = { .type = NLA_U32 },
+ [XFRMA_ETIMER_THRESH] = { .type = NLA_U32 },
+ [XFRMA_SRCADDR] = { .minlen = sizeof(xfrm_address_t) },
+ [XFRMA_MARK] = { .minlen = sizeof(struct xfrm_mark) },
+ [XFRMA_REPLAY_ESN_VAL] = { .minlen = sizeof(struct xfrm_replay_state_esn) },
+};
+
+int xfrmnl_ae_parse(struct nlmsghdr *n, struct xfrmnl_ae **result)
+{
+ struct xfrmnl_ae* ae;
+ struct nlattr *tb[XFRMA_MAX + 1];
+ struct xfrm_aevent_id* ae_id;
+ int err;
+
+ ae = xfrmnl_ae_alloc();
+ if (!ae) {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+
+ ae->ce_msgtype = n->nlmsg_type;
+ ae_id = nlmsg_data(n);
+
+ err = nlmsg_parse(n, sizeof(struct xfrm_aevent_id), tb, XFRMA_MAX, xfrm_ae_policy);
+ if (err < 0)
+ goto errout;
+
+ ae->sa_id.daddr = nl_addr_build(ae_id->sa_id.family, &ae_id->sa_id.daddr, sizeof (ae_id->sa_id.daddr));
+ ae->sa_id.family= ae_id->sa_id.family;
+ ae->sa_id.spi = ntohl(ae_id->sa_id.spi);
+ ae->sa_id.proto = ae_id->sa_id.proto;
+ ae->saddr = nl_addr_build(ae_id->sa_id.family, &ae_id->saddr, sizeof (ae_id->saddr));
+ ae->reqid = ae_id->reqid;
+ ae->flags = ae_id->flags;
+ ae->ce_mask |= (XFRM_AE_ATTR_DADDR | XFRM_AE_ATTR_FAMILY | XFRM_AE_ATTR_SPI |
+ XFRM_AE_ATTR_PROTO | XFRM_AE_ATTR_SADDR | XFRM_AE_ATTR_REQID |
+ XFRM_AE_ATTR_FLAGS);
+
+ if (tb[XFRMA_MARK]) {
+ struct xfrm_mark* m = nla_data(tb[XFRMA_MARK]);
+ ae->mark.m = m->m;
+ ae->mark.v = m->v;
+ ae->ce_mask |= XFRM_AE_ATTR_MARK;
+ }
+
+ if (tb[XFRMA_LTIME_VAL]) {
+ struct xfrm_lifetime_cur* cur = nla_data(tb[XFRMA_LTIME_VAL]);
+ ae->lifetime_cur.bytes = cur->bytes;
+ ae->lifetime_cur.packets = cur->packets;
+ ae->lifetime_cur.add_time = cur->add_time;
+ ae->lifetime_cur.use_time = cur->use_time;
+ ae->ce_mask |= XFRM_AE_ATTR_LIFETIME;
+ }
+
+ if (tb[XFRM_AE_ETHR]) {
+ ae->replay_maxage = *(uint32_t*)nla_data(tb[XFRM_AE_ETHR]);
+ ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXAGE;
+ }
+
+ if (tb[XFRM_AE_RTHR]) {
+ ae->replay_maxdiff = *(uint32_t*)nla_data(tb[XFRM_AE_RTHR]);
+ ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXDIFF;
+ }
+
+ if (tb[XFRMA_REPLAY_ESN_VAL]) {
+ struct xfrm_replay_state_esn* esn = nla_data (tb[XFRMA_REPLAY_ESN_VAL]);
+ uint32_t len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * esn->bmp_len);
+
+ if ((ae->replay_state_esn = calloc (1, len)) == NULL) {
+ err = -ENOMEM;
+ goto errout;
+ }
+ ae->replay_state_esn->oseq = esn->oseq;
+ ae->replay_state_esn->seq = esn->seq;
+ ae->replay_state_esn->oseq_hi = esn->oseq_hi;
+ ae->replay_state_esn->seq_hi = esn->seq_hi;
+ ae->replay_state_esn->replay_window = esn->replay_window;
+ ae->replay_state_esn->bmp_len = esn->bmp_len;
+ memcpy (ae->replay_state_esn->bmp, esn->bmp, sizeof (uint32_t) * esn->bmp_len);
+ ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
+ }
+ else
+ {
+ struct xfrm_replay_state* replay_state = nla_data (tb[XFRMA_REPLAY_VAL]);
+ ae->replay_state.oseq = replay_state->oseq;
+ ae->replay_state.seq = replay_state->seq;
+ ae->replay_state.bitmap = replay_state->bitmap;
+ ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
+
+ ae->replay_state_esn = NULL;
+ }
+
+ *result = ae;
+ return 0;
+
+errout:
+ xfrmnl_ae_put(ae);
+ return err;
+}
+
+static int xfrm_ae_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+ struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+ struct xfrmnl_ae* ae;
+ int err;
+
+ if ((err = xfrmnl_ae_parse(n, &ae)) < 0)
+ return err;
+
+ err = pp->pp_cb((struct nl_object *) ae, pp);
+
+ xfrmnl_ae_put(ae);
+ return err;
+}
+
+/**
+ * @name XFRM AE Get
+ * @{
+ */
+
+int xfrmnl_ae_build_get_request(struct nl_addr* daddr, unsigned int spi, unsigned int protocol,
+ unsigned int mark_mask, unsigned int mark_value, struct nl_msg **result)
+{
+ struct nl_msg *msg;
+ struct xfrm_aevent_id ae_id;
+ struct xfrmnl_mark mark;
+
+ if (!daddr || !spi)
+ {
+ fprintf(stderr, "APPLICATION BUG: %s:%d:%s: A valid destination address, spi must be specified\n",
+ __FILE__, __LINE__, __func__);
+ assert(0);
+ return -NLE_MISSING_ATTR;
+ }
+
+ memset(&ae_id, 0, sizeof(ae_id));
+ memcpy (&ae_id.sa_id.daddr, nl_addr_get_binary_addr (daddr), sizeof (uint8_t) * nl_addr_get_len (daddr));
+ ae_id.sa_id.spi = htonl(spi);
+ ae_id.sa_id.family = nl_addr_get_family (daddr);
+ ae_id.sa_id.proto = protocol;
+
+ if (!(msg = nlmsg_alloc_simple(XFRM_MSG_GETAE, 0)))
+ return -NLE_NOMEM;
+
+ if (nlmsg_append(msg, &ae_id, sizeof(ae_id), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ mark.m = mark_mask;
+ mark.v = mark_value;
+ NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrmnl_mark), &mark);
+
+ *result = msg;
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+}
+
+int xfrmnl_ae_get_kernel(struct nl_sock* sock, struct nl_addr* daddr, unsigned int spi, unsigned int protocol,
+ unsigned int mark_mask, unsigned int mark_value, struct xfrmnl_ae** result)
+{
+ struct nl_msg *msg = NULL;
+ struct nl_object *obj;
+ int err;
+
+ if ((err = xfrmnl_ae_build_get_request(daddr, spi, protocol, mark_mask, mark_value, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto(sock, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ if ((err = nl_pickup(sock, &xfrm_ae_msg_parser, &obj)) < 0)
+ return err;
+
+ /* We have used xfrm_ae_msg_parser(), object is definitely a xfrm ae */
+ *result = (struct xfrmnl_ae *) obj;
+
+ /* If an object has been returned, we also need to wait for the ACK */
+ if (err == 0 && obj)
+ nl_wait_for_ack(sock);
+
+ return 0;
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+static inline int __assign_addr(struct xfrmnl_ae* ae, struct nl_addr **pos,
+ struct nl_addr *new, int flag, int nocheck)
+{
+ if (!nocheck) {
+ if (ae->ce_mask & XFRM_AE_ATTR_FAMILY) {
+ if (nl_addr_get_family (new) != ae->sa_id.family)
+ return -NLE_AF_MISMATCH;
+ } else {
+ ae->sa_id.family = nl_addr_get_family (new);
+ ae->ce_mask |= XFRM_AE_ATTR_FAMILY;
+ }
+ }
+
+ if (*pos)
+ nl_addr_put(*pos);
+
+ nl_addr_get(new);
+ *pos = new;
+
+ ae->ce_mask |= flag;
+
+ return 0;
+}
+
+
+struct nl_addr* xfrmnl_ae_get_daddr (struct xfrmnl_ae* ae)
+{
+ if (ae->ce_mask & XFRM_AE_ATTR_DADDR)
+ return ae->sa_id.daddr;
+ else
+ return NULL;
+}
+
+int xfrmnl_ae_set_daddr (struct xfrmnl_ae* ae, struct nl_addr* addr)
+{
+ return __assign_addr(ae, &ae->sa_id.daddr, addr, XFRM_AE_ATTR_DADDR, 0);
+}
+
+int xfrmnl_ae_get_spi (struct xfrmnl_ae* ae)
+{
+ if (ae->ce_mask & XFRM_AE_ATTR_SPI)
+ return ae->sa_id.spi;
+ else
+ return -1;
+}
+
+int xfrmnl_ae_set_spi (struct xfrmnl_ae* ae, unsigned int spi)
+{
+ ae->sa_id.spi = spi;
+ ae->ce_mask |= XFRM_AE_ATTR_SPI;
+
+ return 0;
+}
+
+int xfrmnl_ae_get_family (struct xfrmnl_ae* ae)
+{
+ if (ae->ce_mask & XFRM_AE_ATTR_FAMILY)
+ return ae->sa_id.family;
+ else
+ return -1;
+}
+
+int xfrmnl_ae_set_family (struct xfrmnl_ae* ae, unsigned int family)
+{
+ ae->sa_id.family = family;
+ ae->ce_mask |= XFRM_AE_ATTR_FAMILY;
+
+ return 0;
+}
+
+int xfrmnl_ae_get_proto (struct xfrmnl_ae* ae)
+{
+ if (ae->ce_mask & XFRM_AE_ATTR_PROTO)
+ return ae->sa_id.proto;
+ else
+ return -1;
+}
+
+int xfrmnl_ae_set_proto (struct xfrmnl_ae* ae, unsigned int protocol)
+{
+ ae->sa_id.proto = protocol;
+ ae->ce_mask |= XFRM_AE_ATTR_PROTO;
+
+ return 0;
+}
+
+struct nl_addr* xfrmnl_ae_get_saddr (struct xfrmnl_ae* ae)
+{
+ if (ae->ce_mask & XFRM_AE_ATTR_SADDR)
+ return ae->saddr;
+ else
+ return NULL;
+}
+
+int xfrmnl_ae_set_saddr (struct xfrmnl_ae* ae, struct nl_addr* addr)
+{
+ return __assign_addr(ae, &ae->saddr, addr, XFRM_AE_ATTR_SADDR, 1);
+}
+
+int xfrmnl_ae_get_flags (struct xfrmnl_ae* ae)
+{
+ if (ae->ce_mask & XFRM_AE_ATTR_FLAGS)
+ return ae->flags;
+ else
+ return -1;
+}
+
+int xfrmnl_ae_set_flags (struct xfrmnl_ae* ae, unsigned int flags)
+{
+ ae->flags = flags;
+ ae->ce_mask |= XFRM_AE_ATTR_FLAGS;
+
+ return 0;
+}
+
+int xfrmnl_ae_get_reqid (struct xfrmnl_ae* ae)
+{
+ if (ae->ce_mask & XFRM_AE_ATTR_REQID)
+ return ae->reqid;
+ else
+ return -1;
+}
+
+int xfrmnl_ae_set_reqid (struct xfrmnl_ae* ae, unsigned int reqid)
+{
+ ae->reqid = reqid;
+ ae->ce_mask |= XFRM_AE_ATTR_REQID;
+
+ return 0;
+}
+
+int xfrmnl_ae_get_mark (struct xfrmnl_ae* ae, unsigned int* mark_mask, unsigned int* mark_value)
+{
+ if (mark_mask == NULL || mark_value == NULL)
+ return -1;
+
+ if (ae->ce_mask & XFRM_AE_ATTR_MARK)
+ {
+ *mark_mask = ae->mark.m;
+ *mark_value = ae->mark.v;
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+int xfrmnl_ae_set_mark (struct xfrmnl_ae* ae, unsigned int value, unsigned int mask)
+{
+ ae->mark.v = value;
+ ae->mark.m = mask;
+ ae->ce_mask |= XFRM_AE_ATTR_MARK;
+
+ return 0;
+}
+
+int xfrmnl_ae_get_curlifetime (struct xfrmnl_ae* ae, unsigned long long int* curr_bytes,
+ unsigned long long int* curr_packets, unsigned long long int* curr_add_time,
+ unsigned long long int* curr_use_time)
+{
+ if (curr_bytes == NULL || curr_packets == NULL || curr_add_time == NULL || curr_use_time == NULL)
+ return -1;
+
+ if (ae->ce_mask & XFRM_AE_ATTR_LIFETIME)
+ {
+ *curr_bytes = ae->lifetime_cur.bytes;
+ *curr_packets = ae->lifetime_cur.packets;
+ *curr_add_time = ae->lifetime_cur.add_time;
+ *curr_use_time = ae->lifetime_cur.use_time;
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+int xfrmnl_ae_set_curlifetime (struct xfrmnl_ae* ae, unsigned long long int curr_bytes,
+ unsigned long long int curr_packets, unsigned long long int curr_add_time,
+ unsigned long long int curr_use_time)
+{
+ ae->lifetime_cur.bytes = curr_bytes;
+ ae->lifetime_cur.packets = curr_packets;
+ ae->lifetime_cur.add_time = curr_add_time;
+ ae->lifetime_cur.use_time = curr_use_time;
+ ae->ce_mask |= XFRM_AE_ATTR_LIFETIME;
+
+ return 0;
+}
+
+int xfrmnl_ae_get_replay_maxage (struct xfrmnl_ae* ae)
+{
+ if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_MAXAGE)
+ return ae->replay_maxage;
+ else
+ return -1;
+}
+
+int xfrmnl_ae_set_replay_maxage (struct xfrmnl_ae* ae, unsigned int replay_maxage)
+{
+ ae->replay_maxage = replay_maxage;
+ ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXAGE;
+
+ return 0;
+}
+
+int xfrmnl_ae_get_replay_maxdiff (struct xfrmnl_ae* ae)
+{
+ if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_MAXDIFF)
+ return ae->replay_maxdiff;
+ else
+ return -1;
+}
+
+int xfrmnl_ae_set_replay_maxdiff (struct xfrmnl_ae* ae, unsigned int replay_maxdiff)
+{
+ ae->replay_maxdiff = replay_maxdiff;
+ ae->ce_mask |= XFRM_AE_ATTR_REPLAY_MAXDIFF;
+
+ return 0;
+}
+
+int xfrmnl_ae_get_replay_state (struct xfrmnl_ae* ae, unsigned int* oseq, unsigned int* seq, unsigned int* bmp)
+{
+ if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_STATE)
+ {
+ if (ae->replay_state_esn == NULL)
+ {
+ *oseq = ae->replay_state.oseq;
+ *seq = ae->replay_state.seq;
+ *bmp = ae->replay_state.bitmap;
+
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ return -1;
+}
+
+int xfrmnl_ae_set_replay_state (struct xfrmnl_ae* ae, unsigned int oseq, unsigned int seq, unsigned int bitmap)
+{
+ ae->replay_state.oseq = oseq;
+ ae->replay_state.seq = seq;
+ ae->replay_state.bitmap = bitmap;
+ ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
+
+ return 0;
+}
+
+int xfrmnl_ae_get_replay_state_esn(struct xfrmnl_ae* ae, unsigned int* oseq, unsigned int* seq, unsigned int* oseq_hi,
+ unsigned int* seq_hi, unsigned int* replay_window, unsigned int* bmp_len, unsigned int* bmp)
+{
+ if (ae->ce_mask & XFRM_AE_ATTR_REPLAY_STATE)
+ {
+ if (ae->replay_state_esn)
+ {
+ *oseq = ae->replay_state_esn->oseq;
+ *seq = ae->replay_state_esn->seq;
+ *oseq_hi= ae->replay_state_esn->oseq_hi;
+ *seq_hi = ae->replay_state_esn->seq_hi;
+ *replay_window = ae->replay_state_esn->replay_window;
+ *bmp_len = ae->replay_state_esn->bmp_len; // In number of 32 bit words
+ memcpy (bmp, ae->replay_state_esn->bmp, ae->replay_state_esn->bmp_len * sizeof (uint32_t));
+
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ return -1;
+}
+
+int xfrmnl_ae_set_replay_state_esn(struct xfrmnl_ae* ae, unsigned int oseq, unsigned int seq,
+ unsigned int oseq_hi, unsigned int seq_hi, unsigned int replay_window,
+ unsigned int bmp_len, unsigned int* bmp)
+{
+ /* Free the old replay ESN state and allocate new one */
+ if (ae->replay_state_esn)
+ free (ae->replay_state_esn);
+
+ if ((ae->replay_state_esn = calloc (1, sizeof (struct xfrmnl_replay_state_esn) + sizeof (uint32_t) * bmp_len)) == NULL)
+ return -1;
+
+ ae->replay_state_esn->oseq = oseq;
+ ae->replay_state_esn->seq = seq;
+ ae->replay_state_esn->oseq_hi = oseq_hi;
+ ae->replay_state_esn->seq_hi = seq_hi;
+ ae->replay_state_esn->replay_window = replay_window;
+ ae->replay_state_esn->bmp_len = bmp_len; // In number of 32 bit words
+ memcpy (ae->replay_state_esn->bmp, bmp, bmp_len * sizeof (uint32_t));
+ ae->ce_mask |= XFRM_AE_ATTR_REPLAY_STATE;
+
+ return 0;
+}
+
+/** @} */
+
+static struct nl_object_ops xfrm_ae_obj_ops = {
+ .oo_name = "xfrm/ae",
+ .oo_size = sizeof(struct xfrmnl_ae),
+ .oo_free_data = xfrm_ae_free_data,
+ .oo_clone = xfrm_ae_clone,
+ .oo_dump = {
+ [NL_DUMP_LINE] = xfrm_ae_dump_line,
+ [NL_DUMP_DETAILS] = xfrm_ae_dump_details,
+ [NL_DUMP_STATS] = xfrm_ae_dump_stats,
+ },
+ .oo_compare = xfrm_ae_compare,
+ .oo_attrs2str = xfrm_ae_attrs2str,
+ .oo_id_attrs = (XFRM_AE_ATTR_DADDR | XFRM_AE_ATTR_SPI | XFRM_AE_ATTR_PROTO),
+};
+
+/** @} */
+
diff --git a/lib/xfrm/lifetime.c b/lib/xfrm/lifetime.c
new file mode 100644
index 00000000..db761d64
--- /dev/null
+++ b/lib/xfrm/lifetime.c
@@ -0,0 +1,275 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**
+ * @ingroup xfrmnl
+ * @defgroup XFRM Lifetime Configuration Object
+ *
+ * Abstract data type representing XFRM SA lifetime properties
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/xfrm/lifetime.h>
+ * ~~~~
+ */
+
+#include <netlink/xfrm/lifetime.h>
+#include <netlink-private/netlink.h>
+
+static void ltime_cfg_destroy(struct xfrmnl_ltime_cfg* ltime)
+{
+ if (!ltime)
+ return;
+
+ if (ltime->refcnt != 1)
+ {
+ fprintf(stderr, "BUG: %s:%d\n", __FILE__, __LINE__);
+ assert(0);
+ }
+
+ free(ltime);
+}
+
+/**
+ * @name Creating Selector
+ * @{
+ */
+
+/**
+ * Allocate new lifetime config object.
+ * @return Newly allocated lifetime config object or NULL
+ */
+struct xfrmnl_ltime_cfg* xfrmnl_ltime_cfg_alloc()
+{
+ struct xfrmnl_ltime_cfg* ltime;
+
+ ltime = calloc(1, sizeof(struct xfrmnl_ltime_cfg));
+ if (!ltime)
+ return NULL;
+
+ ltime->refcnt = 1;
+
+ return ltime;
+}
+
+/**
+ * Clone existing lifetime config object.
+ * @arg ltime Selector object.
+ * @return Newly allocated lifetime config object being a duplicate of the
+ * specified lifetime config object or NULL if a failure occured.
+ */
+struct xfrmnl_ltime_cfg* xfrmnl_ltime_cfg_clone(struct xfrmnl_ltime_cfg* ltime)
+{
+ struct xfrmnl_ltime_cfg* new;
+
+ new = xfrmnl_ltime_cfg_alloc();
+ if (new)
+ memcpy ((void*)new, (void*)ltime, sizeof (struct xfrmnl_ltime_cfg));
+
+ return new;
+}
+
+/** @} */
+
+/**
+ * @name Managing Usage References
+ * @{
+ */
+
+struct xfrmnl_ltime_cfg* xfrmnl_ltime_cfg_get(struct xfrmnl_ltime_cfg* ltime)
+{
+ ltime->refcnt++;
+
+ return ltime;
+}
+
+void xfrmnl_ltime_cfg_put(struct xfrmnl_ltime_cfg* ltime)
+{
+ if (!ltime)
+ return;
+
+ if (ltime->refcnt == 1)
+ ltime_cfg_destroy(ltime);
+ else
+ ltime->refcnt--;
+}
+
+/**
+ * Check whether an lifetime config object is shared.
+ * @arg addr Selector object.
+ * @return Non-zero if the lifetime config object is shared, otherwise 0.
+ */
+int xfrmnl_ltime_cfg_shared(struct xfrmnl_ltime_cfg* ltime)
+{
+ return ltime->refcnt > 1;
+}
+
+/** @} */
+
+/**
+ * @name Miscellaneous
+ * @{
+ */
+
+/**
+ * Compares two lifetime config objects.
+ * @arg a A lifetime config object.
+ * @arg b Another lifetime config object.
+ *
+ * @return Non zero if difference is found, 0 otherwise if both
+ * the objects are identical.
+ */
+int xfrmnl_ltime_cfg_cmp(struct xfrmnl_ltime_cfg* a, struct xfrmnl_ltime_cfg* b)
+{
+ /* Check for any differences */
+ if ((a->soft_byte_limit != b->soft_byte_limit) ||
+ (a->soft_packet_limit != b->soft_packet_limit) ||
+ (a->hard_byte_limit != b->hard_byte_limit) ||
+ (a->hard_packet_limit != b->hard_packet_limit) ||
+ (a->soft_add_expires_seconds != b->soft_add_expires_seconds) ||
+ (a->hard_add_expires_seconds != b->hard_add_expires_seconds) ||
+ (a->soft_use_expires_seconds != b->soft_use_expires_seconds) ||
+ (a->hard_use_expires_seconds != b->hard_use_expires_seconds))
+ return 1;
+
+ /* The objects are identical */
+ return 0;
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+unsigned long long xfrmnl_ltime_cfg_get_soft_bytelimit (struct xfrmnl_ltime_cfg* ltime)
+{
+ return ltime->soft_byte_limit;
+}
+
+int xfrmnl_ltime_cfg_set_soft_bytelimit (struct xfrmnl_ltime_cfg* ltime, unsigned long long soft_byte_limit)
+{
+ ltime->soft_byte_limit = soft_byte_limit;
+
+ return 0;
+}
+
+unsigned long long xfrmnl_ltime_cfg_get_hard_bytelimit (struct xfrmnl_ltime_cfg* ltime)
+{
+ return ltime->hard_byte_limit;
+}
+
+int xfrmnl_ltime_cfg_set_hard_bytelimit (struct xfrmnl_ltime_cfg* ltime, unsigned long long hard_byte_limit)
+{
+ ltime->hard_byte_limit = hard_byte_limit;
+
+ return 0;
+}
+
+unsigned long long xfrmnl_ltime_cfg_get_soft_packetlimit (struct xfrmnl_ltime_cfg* ltime)
+{
+ return ltime->soft_packet_limit;
+}
+
+int xfrmnl_ltime_cfg_set_soft_packetlimit (struct xfrmnl_ltime_cfg* ltime, unsigned long long soft_packet_limit)
+{
+ ltime->soft_packet_limit = soft_packet_limit;
+
+ return 0;
+}
+
+unsigned long long xfrmnl_ltime_cfg_get_hard_packetlimit (struct xfrmnl_ltime_cfg* ltime)
+{
+ return ltime->hard_packet_limit;
+}
+
+int xfrmnl_ltime_cfg_set_hard_packetlimit (struct xfrmnl_ltime_cfg* ltime, unsigned long long hard_packet_limit)
+{
+ ltime->hard_packet_limit = hard_packet_limit;
+
+ return 0;
+}
+
+unsigned long long xfrmnl_ltime_cfg_get_soft_addexpires (struct xfrmnl_ltime_cfg* ltime)
+{
+ return ltime->soft_add_expires_seconds;
+}
+
+int xfrmnl_ltime_cfg_set_soft_addexpires (struct xfrmnl_ltime_cfg* ltime, unsigned long long soft_add_expires_seconds)
+{
+ ltime->soft_add_expires_seconds = soft_add_expires_seconds;
+
+ return 0;
+}
+
+unsigned long long xfrmnl_ltime_cfg_get_hard_addexpires (struct xfrmnl_ltime_cfg* ltime)
+{
+ return ltime->hard_add_expires_seconds;
+}
+
+int xfrmnl_ltime_cfg_set_hard_addexpires (struct xfrmnl_ltime_cfg* ltime, unsigned long long hard_add_expires_seconds)
+{
+ ltime->hard_add_expires_seconds = hard_add_expires_seconds;
+
+ return 0;
+}
+
+unsigned long long xfrmnl_ltime_cfg_get_soft_useexpires (struct xfrmnl_ltime_cfg* ltime)
+{
+ return ltime->soft_use_expires_seconds;
+}
+
+int xfrmnl_ltime_cfg_set_soft_useexpires (struct xfrmnl_ltime_cfg* ltime, unsigned long long soft_use_expires_seconds)
+{
+ ltime->soft_use_expires_seconds = soft_use_expires_seconds;
+
+ return 0;
+}
+
+unsigned long long xfrmnl_ltime_cfg_get_hard_useexpires (struct xfrmnl_ltime_cfg* ltime)
+{
+ return ltime->hard_use_expires_seconds;
+}
+
+int xfrmnl_ltime_cfg_set_hard_useexpires (struct xfrmnl_ltime_cfg* ltime, unsigned long long hard_use_expires_seconds)
+{
+ ltime->hard_use_expires_seconds = hard_use_expires_seconds;
+
+ return 0;
+}
+
+/** @} */
diff --git a/lib/xfrm/sa.c b/lib/xfrm/sa.c
new file mode 100644
index 00000000..48265ba4
--- /dev/null
+++ b/lib/xfrm/sa.c
@@ -0,0 +1,2233 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**
+ * @ingroup xfrmnl
+ * @defgroup sa Security Association
+ * @brief
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/object.h>
+#include <netlink/xfrm/sa.h>
+#include <netlink/xfrm/selector.h>
+#include <netlink/xfrm/lifetime.h>
+#include <time.h>
+
+#include "netlink-private/utils.h"
+
+/** @cond SKIP */
+#define XFRM_SA_ATTR_SEL 0x01
+#define XFRM_SA_ATTR_DADDR 0x02
+#define XFRM_SA_ATTR_SPI 0x04
+#define XFRM_SA_ATTR_PROTO 0x08
+#define XFRM_SA_ATTR_SADDR 0x10
+#define XFRM_SA_ATTR_LTIME_CFG 0x20
+#define XFRM_SA_ATTR_LTIME_CUR 0x40
+#define XFRM_SA_ATTR_STATS 0x80
+#define XFRM_SA_ATTR_SEQ 0x100
+#define XFRM_SA_ATTR_REQID 0x200
+#define XFRM_SA_ATTR_FAMILY 0x400
+#define XFRM_SA_ATTR_MODE 0x800
+#define XFRM_SA_ATTR_REPLAY_WIN 0x1000
+#define XFRM_SA_ATTR_FLAGS 0x2000
+#define XFRM_SA_ATTR_ALG_AEAD 0x4000
+#define XFRM_SA_ATTR_ALG_AUTH 0x8000
+#define XFRM_SA_ATTR_ALG_CRYPT 0x10000
+#define XFRM_SA_ATTR_ALG_COMP 0x20000
+#define XFRM_SA_ATTR_ENCAP 0x40000
+#define XFRM_SA_ATTR_TFCPAD 0x80000
+#define XFRM_SA_ATTR_COADDR 0x100000
+#define XFRM_SA_ATTR_MARK 0x200000
+#define XFRM_SA_ATTR_SECCTX 0x400000
+#define XFRM_SA_ATTR_REPLAY_MAXAGE 0x800000
+#define XFRM_SA_ATTR_REPLAY_MAXDIFF 0x1000000
+#define XFRM_SA_ATTR_REPLAY_STATE 0x2000000
+#define XFRM_SA_ATTR_EXPIRE 0x4000000
+
+static struct nl_cache_ops xfrmnl_sa_ops;
+static struct nl_object_ops xfrm_sa_obj_ops;
+/** @endcond */
+
+static void xfrm_sa_alloc_data(struct nl_object *c)
+{
+ struct xfrmnl_sa* sa = nl_object_priv (c);
+
+ if ((sa->sel = xfrmnl_sel_alloc ()) == NULL)
+ return;
+
+ if ((sa->lft = xfrmnl_ltime_cfg_alloc ()) == NULL)
+ return;
+}
+
+static void xfrm_sa_free_data(struct nl_object *c)
+{
+ struct xfrmnl_sa* sa = nl_object_priv (c);
+
+ if (sa == NULL)
+ return;
+
+ xfrmnl_sel_put (sa->sel);
+ xfrmnl_ltime_cfg_put (sa->lft);
+ nl_addr_put (sa->id.daddr);
+ nl_addr_put (sa->saddr);
+
+ if (sa->aead)
+ free (sa->aead);
+ if (sa->auth)
+ free (sa->auth);
+ if (sa->crypt)
+ free (sa->crypt);
+ if (sa->comp)
+ free (sa->comp);
+ if (sa->encap) {
+ if (sa->encap->encap_oa)
+ nl_addr_put(sa->encap->encap_oa);
+ free(sa->encap);
+ }
+ if (sa->coaddr)
+ nl_addr_put (sa->coaddr);
+ if (sa->sec_ctx)
+ free (sa->sec_ctx);
+ if (sa->replay_state_esn)
+ free (sa->replay_state_esn);
+}
+
+static int xfrm_sa_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+ struct xfrmnl_sa* dst = nl_object_priv(_dst);
+ struct xfrmnl_sa* src = nl_object_priv(_src);
+ uint32_t len = 0;
+
+ if (src->sel)
+ if ((dst->sel = xfrmnl_sel_clone (src->sel)) == NULL)
+ return -NLE_NOMEM;
+
+ if (src->lft)
+ if ((dst->lft = xfrmnl_ltime_cfg_clone (src->lft)) == NULL)
+ return -NLE_NOMEM;
+
+ if (src->id.daddr)
+ if ((dst->id.daddr = nl_addr_clone (src->id.daddr)) == NULL)
+ return -NLE_NOMEM;
+
+ if (src->saddr)
+ if ((dst->saddr = nl_addr_clone (src->saddr)) == NULL)
+ return -NLE_NOMEM;
+
+ if (src->aead)
+ {
+ len = sizeof (struct xfrmnl_algo_aead) + ((src->aead->alg_key_len + 7) / 8);
+ if ((dst->aead = calloc (1, len)) == NULL)
+ return -NLE_NOMEM;
+ memcpy ((void *)dst->aead, (void *)src->aead, len);
+ }
+
+ if (src->auth)
+ {
+ len = sizeof (struct xfrmnl_algo_auth) + ((src->auth->alg_key_len + 7) / 8);
+ if ((dst->auth = calloc (1, len)) == NULL)
+ return -NLE_NOMEM;
+ memcpy ((void *)dst->auth, (void *)src->auth, len);
+ }
+
+ if (src->crypt)
+ {
+ len = sizeof (struct xfrmnl_algo) + ((src->crypt->alg_key_len + 7) / 8);
+ if ((dst->crypt = calloc (1, len)) == NULL)
+ return -NLE_NOMEM;
+ memcpy ((void *)dst->crypt, (void *)src->crypt, len);
+ }
+
+ if (src->comp)
+ {
+ len = sizeof (struct xfrmnl_algo) + ((src->comp->alg_key_len + 7) / 8);
+ if ((dst->comp = calloc (1, len)) == NULL)
+ return -NLE_NOMEM;
+ memcpy ((void *)dst->comp, (void *)src->comp, len);
+ }
+
+ if (src->encap)
+ {
+ len = sizeof (struct xfrmnl_encap_tmpl);
+ if ((dst->encap = calloc (1, len)) == NULL)
+ return -NLE_NOMEM;
+ memcpy ((void *)dst->encap, (void *)src->encap, len);
+ }
+
+ if (src->coaddr)
+ if ((dst->coaddr = nl_addr_clone (src->coaddr)) == NULL)
+ return -NLE_NOMEM;
+
+ if (src->sec_ctx)
+ {
+ len = sizeof (*src->sec_ctx) + src->sec_ctx->ctx_len;
+ if ((dst->sec_ctx = calloc (1, len)) == NULL)
+ return -NLE_NOMEM;
+ memcpy ((void *)dst->sec_ctx, (void *)src->sec_ctx, len);
+ }
+
+ if (src->replay_state_esn)
+ {
+ len = sizeof (struct xfrmnl_replay_state_esn) + (src->replay_state_esn->bmp_len * sizeof (uint32_t));
+ if ((dst->replay_state_esn = calloc (1, len)) == NULL)
+ return -NLE_NOMEM;
+ memcpy ((void *)dst->replay_state_esn, (void *)src->replay_state_esn, len);
+ }
+
+ return 0;
+}
+
+static uint64_t xfrm_sa_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
+{
+ struct xfrmnl_sa* a = (struct xfrmnl_sa *) _a;
+ struct xfrmnl_sa* b = (struct xfrmnl_sa *) _b;
+ uint64_t diff = 0;
+ int found = 0;
+
+#define XFRM_SA_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, XFRM_SA_ATTR_##ATTR, a, b, EXPR)
+ diff |= XFRM_SA_DIFF(SEL, xfrmnl_sel_cmp(a->sel, b->sel));
+ diff |= XFRM_SA_DIFF(DADDR, nl_addr_cmp(a->id.daddr, b->id.daddr));
+ diff |= XFRM_SA_DIFF(SPI, a->id.spi != b->id.spi);
+ diff |= XFRM_SA_DIFF(PROTO, a->id.proto != b->id.proto);
+ diff |= XFRM_SA_DIFF(SADDR, nl_addr_cmp(a->saddr, b->saddr));
+ diff |= XFRM_SA_DIFF(LTIME_CFG, xfrmnl_ltime_cfg_cmp(a->lft, b->lft));
+ diff |= XFRM_SA_DIFF(REQID, a->reqid != b->reqid);
+ diff |= XFRM_SA_DIFF(FAMILY,a->family != b->family);
+ diff |= XFRM_SA_DIFF(MODE,a->mode != b->mode);
+ diff |= XFRM_SA_DIFF(REPLAY_WIN,a->replay_window != b->replay_window);
+ diff |= XFRM_SA_DIFF(FLAGS,a->flags != b->flags);
+ diff |= XFRM_SA_DIFF(ALG_AEAD,(strcmp(a->aead->alg_name, b->aead->alg_name) ||
+ (a->aead->alg_key_len != b->aead->alg_key_len) ||
+ (a->aead->alg_icv_len != b->aead->alg_icv_len) ||
+ memcmp(a->aead->alg_key, b->aead->alg_key,
+ ((a->aead->alg_key_len + 7)/8))));
+ diff |= XFRM_SA_DIFF(ALG_AUTH,(strcmp(a->auth->alg_name, b->auth->alg_name) ||
+ (a->auth->alg_key_len != b->auth->alg_key_len) ||
+ (a->auth->alg_trunc_len != b->auth->alg_trunc_len) ||
+ memcmp(a->auth->alg_key, b->auth->alg_key,
+ ((a->auth->alg_key_len + 7)/8))));
+ diff |= XFRM_SA_DIFF(ALG_CRYPT,(strcmp(a->crypt->alg_name, b->crypt->alg_name) ||
+ (a->crypt->alg_key_len != b->crypt->alg_key_len) ||
+ memcmp(a->crypt->alg_key, b->crypt->alg_key,
+ ((a->crypt->alg_key_len + 7)/8))));
+ diff |= XFRM_SA_DIFF(ALG_COMP,(strcmp(a->comp->alg_name, b->comp->alg_name) ||
+ (a->comp->alg_key_len != b->comp->alg_key_len) ||
+ memcmp(a->comp->alg_key, b->comp->alg_key,
+ ((a->comp->alg_key_len + 7)/8))));
+ diff |= XFRM_SA_DIFF(ENCAP,((a->encap->encap_type != b->encap->encap_type) ||
+ (a->encap->encap_sport != b->encap->encap_sport) ||
+ (a->encap->encap_dport != b->encap->encap_dport) ||
+ nl_addr_cmp(a->encap->encap_oa, b->encap->encap_oa)));
+ diff |= XFRM_SA_DIFF(TFCPAD,a->tfcpad != b->tfcpad);
+ diff |= XFRM_SA_DIFF(COADDR,nl_addr_cmp(a->coaddr, b->coaddr));
+ diff |= XFRM_SA_DIFF(MARK,(a->mark.m != b->mark.m) ||
+ (a->mark.v != b->mark.v));
+ diff |= XFRM_SA_DIFF(SECCTX,((a->sec_ctx->ctx_doi != b->sec_ctx->ctx_doi) ||
+ (a->sec_ctx->ctx_alg != b->sec_ctx->ctx_alg) ||
+ (a->sec_ctx->ctx_len != b->sec_ctx->ctx_len) ||
+ strcmp(a->sec_ctx->ctx, b->sec_ctx->ctx)));
+ diff |= XFRM_SA_DIFF(REPLAY_MAXAGE,a->replay_maxage != b->replay_maxage);
+ diff |= XFRM_SA_DIFF(REPLAY_MAXDIFF,a->replay_maxdiff != b->replay_maxdiff);
+ diff |= XFRM_SA_DIFF(EXPIRE,a->hard != b->hard);
+
+ /* Compare replay states */
+ found = AVAILABLE_MISMATCH (a, b, XFRM_SA_ATTR_REPLAY_STATE);
+ if (found == 0) // attribute exists in both objects
+ {
+ if (((a->replay_state_esn != NULL) && (b->replay_state_esn == NULL)) ||
+ ((a->replay_state_esn == NULL) && (b->replay_state_esn != NULL)))
+ found |= 1;
+
+ if (found == 0) // same replay type. compare actual values
+ {
+ if (a->replay_state_esn)
+ {
+ if (a->replay_state_esn->bmp_len != b->replay_state_esn->bmp_len)
+ diff |= 1;
+ else
+ {
+ uint32_t len = sizeof (struct xfrmnl_replay_state_esn) +
+ (a->replay_state_esn->bmp_len * sizeof (uint32_t));
+ diff |= memcmp (a->replay_state_esn, b->replay_state_esn, len);
+ }
+ }
+ else
+ {
+ if ((a->replay_state.oseq != b->replay_state.oseq) ||
+ (a->replay_state.seq != b->replay_state.seq) ||
+ (a->replay_state.bitmap != b->replay_state.bitmap))
+ diff |= 1;
+ }
+ }
+ }
+#undef XFRM_SA_DIFF
+
+ return diff;
+}
+
+/**
+ * @name XFRM SA Attribute Translations
+ * @{
+ */
+static const struct trans_tbl sa_attrs[] = {
+ __ADD(XFRM_SA_ATTR_SEL, selector),
+ __ADD(XFRM_SA_ATTR_DADDR, daddr),
+ __ADD(XFRM_SA_ATTR_SPI, spi),
+ __ADD(XFRM_SA_ATTR_PROTO, proto),
+ __ADD(XFRM_SA_ATTR_SADDR, saddr),
+ __ADD(XFRM_SA_ATTR_LTIME_CFG, lifetime_cfg),
+ __ADD(XFRM_SA_ATTR_LTIME_CUR, lifetime_cur),
+ __ADD(XFRM_SA_ATTR_STATS, stats),
+ __ADD(XFRM_SA_ATTR_SEQ, seqnum),
+ __ADD(XFRM_SA_ATTR_REQID, reqid),
+ __ADD(XFRM_SA_ATTR_FAMILY, family),
+ __ADD(XFRM_SA_ATTR_MODE, mode),
+ __ADD(XFRM_SA_ATTR_REPLAY_WIN, replay_window),
+ __ADD(XFRM_SA_ATTR_FLAGS, flags),
+ __ADD(XFRM_SA_ATTR_ALG_AEAD, alg_aead),
+ __ADD(XFRM_SA_ATTR_ALG_AUTH, alg_auth),
+ __ADD(XFRM_SA_ATTR_ALG_CRYPT, alg_crypto),
+ __ADD(XFRM_SA_ATTR_ALG_COMP, alg_comp),
+ __ADD(XFRM_SA_ATTR_ENCAP, encap),
+ __ADD(XFRM_SA_ATTR_TFCPAD, tfcpad),
+ __ADD(XFRM_SA_ATTR_COADDR, coaddr),
+ __ADD(XFRM_SA_ATTR_MARK, mark),
+ __ADD(XFRM_SA_ATTR_SECCTX, sec_ctx),
+ __ADD(XFRM_SA_ATTR_REPLAY_MAXAGE, replay_maxage),
+ __ADD(XFRM_SA_ATTR_REPLAY_MAXDIFF, replay_maxdiff),
+ __ADD(XFRM_SA_ATTR_REPLAY_STATE, replay_state),
+ __ADD(XFRM_SA_ATTR_EXPIRE, expire),
+};
+
+static char* xfrm_sa_attrs2str(int attrs, char *buf, size_t len)
+{
+ return __flags2str (attrs, buf, len, sa_attrs, ARRAY_SIZE(sa_attrs));
+}
+/** @} */
+
+/**
+ * @name XFRM SA Flags Translations
+ * @{
+ */
+static const struct trans_tbl sa_flags[] = {
+ __ADD(XFRM_STATE_NOECN, no ecn),
+ __ADD(XFRM_STATE_DECAP_DSCP, decap dscp),
+ __ADD(XFRM_STATE_NOPMTUDISC, no pmtu discovery),
+ __ADD(XFRM_STATE_WILDRECV, wild receive),
+ __ADD(XFRM_STATE_ICMP, icmp),
+ __ADD(XFRM_STATE_AF_UNSPEC, unspecified),
+ __ADD(XFRM_STATE_ALIGN4, align4),
+ __ADD(XFRM_STATE_ESN, esn),
+};
+
+char* xfrmnl_sa_flags2str(int flags, char *buf, size_t len)
+{
+ return __flags2str (flags, buf, len, sa_flags, ARRAY_SIZE(sa_flags));
+}
+
+int xfrmnl_sa_str2flag(const char *name)
+{
+ return __str2flags (name, sa_flags, ARRAY_SIZE(sa_flags));
+}
+/** @} */
+
+/**
+ * @name XFRM SA Mode Translations
+ * @{
+ */
+static const struct trans_tbl sa_modes[] = {
+ __ADD(XFRM_MODE_TRANSPORT, transport),
+ __ADD(XFRM_MODE_TUNNEL, tunnel),
+ __ADD(XFRM_MODE_ROUTEOPTIMIZATION, route optimization),
+ __ADD(XFRM_MODE_IN_TRIGGER, in trigger),
+ __ADD(XFRM_MODE_BEET, beet),
+};
+
+char* xfrmnl_sa_mode2str(int mode, char *buf, size_t len)
+{
+ return __type2str (mode, buf, len, sa_modes, ARRAY_SIZE(sa_modes));
+}
+
+int xfrmnl_sa_str2mode(const char *name)
+{
+ return __str2type (name, sa_modes, ARRAY_SIZE(sa_modes));
+}
+/** @} */
+
+
+static void xfrm_sa_dump_line(struct nl_object *a, struct nl_dump_params *p)
+{
+ char dst[INET6_ADDRSTRLEN+5], src[INET6_ADDRSTRLEN+5];
+ struct xfrmnl_sa* sa = (struct xfrmnl_sa *) a;
+ char flags[128], mode[128];
+ time_t add_time, use_time;
+ struct tm *add_time_tm, *use_time_tm;
+
+ nl_dump_line(p, "src %s dst %s family: %s\n", nl_addr2str(sa->saddr, src, sizeof(src)),
+ nl_addr2str(sa->id.daddr, dst, sizeof(dst)),
+ nl_af2str (sa->family, flags, sizeof (flags)));
+
+ nl_dump_line(p, "\tproto %s spi 0x%x reqid %u\n",
+ nl_ip_proto2str (sa->id.proto, flags, sizeof(flags)),
+ sa->id.spi, sa->reqid);
+
+ xfrmnl_sa_flags2str(sa->flags, flags, sizeof (flags));
+ xfrmnl_sa_mode2str(sa->mode, mode, sizeof (mode));
+ nl_dump_line(p, "\tmode: %s flags: %s (0x%x) seq: %u replay window: %u\n",
+ mode, flags, sa->flags, sa->seq, sa->replay_window);
+
+ nl_dump_line(p, "\tlifetime configuration: \n");
+ if (sa->lft->soft_byte_limit == XFRM_INF)
+ sprintf (flags, "INF");
+ else
+ sprintf (flags, "%" PRIu64, sa->lft->soft_byte_limit);
+ if (sa->lft->soft_packet_limit == XFRM_INF)
+ sprintf (mode, "INF");
+ else
+ sprintf (mode, "%" PRIu64, sa->lft->soft_packet_limit);
+ nl_dump_line(p, "\t\tsoft limit: %s (bytes), %s (packets)\n", flags, mode);
+ if (sa->lft->hard_byte_limit == XFRM_INF)
+ sprintf (flags, "INF");
+ else
+ sprintf (flags, "%" PRIu64, sa->lft->hard_byte_limit);
+ if (sa->lft->hard_packet_limit == XFRM_INF)
+ sprintf (mode, "INF");
+ else
+ sprintf (mode, "%" PRIu64, sa->lft->hard_packet_limit);
+ nl_dump_line(p, "\t\thard limit: %s (bytes), %s (packets)\n", flags, mode);
+ nl_dump_line(p, "\t\tsoft add_time: %llu (seconds), soft use_time: %llu (seconds) \n",
+ sa->lft->soft_add_expires_seconds, sa->lft->soft_use_expires_seconds);
+ nl_dump_line(p, "\t\thard add_time: %llu (seconds), hard use_time: %llu (seconds) \n",
+ sa->lft->hard_add_expires_seconds, sa->lft->hard_use_expires_seconds);
+
+ nl_dump_line(p, "\tlifetime current: \n");
+ nl_dump_line(p, "\t\t%llu bytes, %llu packets\n", sa->curlft.bytes, sa->curlft.packets);
+ if (sa->curlft.add_time != 0)
+ {
+ add_time = sa->curlft.add_time;
+ add_time_tm = gmtime (&add_time);
+ strftime (flags, 128, "%Y-%m-%d %H-%M-%S", add_time_tm);
+ }
+ else
+ {
+ sprintf (flags, "%s", "-");
+ }
+
+ if (sa->curlft.use_time != 0)
+ {
+ use_time = sa->curlft.use_time;
+ use_time_tm = gmtime (&use_time);
+ strftime (mode, 128, "%Y-%m-%d %H-%M-%S", use_time_tm);
+ }
+ else
+ {
+ sprintf (mode, "%s", "-");
+ }
+ nl_dump_line(p, "\t\tadd_time: %s, use_time: %s\n", flags, mode);
+
+ if (sa->aead)
+ {
+ nl_dump_line(p, "\tAEAD Algo: \n");
+ nl_dump_line(p, "\t\tName: %s Key len(bits): %u ICV Len(bits): %u\n",
+ sa->aead->alg_name, sa->aead->alg_key_len, sa->aead->alg_icv_len);
+ }
+
+ if (sa->auth)
+ {
+ nl_dump_line(p, "\tAuth Algo: \n");
+ nl_dump_line(p, "\t\tName: %s Key len(bits): %u Trunc len(bits): %u\n",
+ sa->auth->alg_name, sa->auth->alg_key_len, sa->auth->alg_trunc_len);
+ }
+
+ if (sa->crypt)
+ {
+ nl_dump_line(p, "\tEncryption Algo: \n");
+ nl_dump_line(p, "\t\tName: %s Key len(bits): %u\n",
+ sa->crypt->alg_name, sa->crypt->alg_key_len);
+ }
+
+ if (sa->comp)
+ {
+ nl_dump_line(p, "\tCompression Algo: \n");
+ nl_dump_line(p, "\t\tName: %s Key len(bits): %u\n",
+ sa->comp->alg_name, sa->comp->alg_key_len);
+ }
+
+ if (sa->encap)
+ {
+ nl_dump_line(p, "\tEncapsulation template: \n");
+ nl_dump_line(p, "\t\tType: %d Src port: %d Dst port: %d Encap addr: %s\n",
+ sa->encap->encap_type, sa->encap->encap_sport, sa->encap->encap_dport,
+ nl_addr2str (sa->encap->encap_oa, dst, sizeof (dst)));
+ }
+
+ if (sa->ce_mask & XFRM_SA_ATTR_TFCPAD)
+ nl_dump_line(p, "\tTFC Pad: %u\n", sa->tfcpad);
+
+ if (sa->ce_mask & XFRM_SA_ATTR_COADDR)
+ nl_dump_line(p, "\tCO Address: %s\n", nl_addr2str (sa->coaddr, dst, sizeof (dst)));
+
+ if (sa->ce_mask & XFRM_SA_ATTR_MARK)
+ nl_dump_line(p, "\tMark mask: 0x%x Mark value: 0x%x\n", sa->mark.m, sa->mark.v);
+
+ if (sa->ce_mask & XFRM_SA_ATTR_SECCTX)
+ nl_dump_line(p, "\tDOI: %d Algo: %d Len: %u ctx: %s\n", sa->sec_ctx->ctx_doi,
+ sa->sec_ctx->ctx_alg, sa->sec_ctx->ctx_len, sa->sec_ctx->ctx);
+
+ nl_dump_line(p, "\treplay info: \n");
+ nl_dump_line(p, "\t\tmax age %u max diff %u \n", sa->replay_maxage, sa->replay_maxdiff);
+
+ if (sa->ce_mask & XFRM_SA_ATTR_REPLAY_STATE)
+ {
+ nl_dump_line(p, "\treplay state info: \n");
+ if (sa->replay_state_esn)
+ {
+ nl_dump_line(p, "\t\toseq %u seq %u oseq_hi %u seq_hi %u replay window: %u \n",
+ sa->replay_state_esn->oseq, sa->replay_state_esn->seq,
+ sa->replay_state_esn->oseq_hi, sa->replay_state_esn->seq_hi,
+ sa->replay_state_esn->replay_window);
+ }
+ else
+ {
+ nl_dump_line(p, "\t\toseq %u seq %u bitmap: %u \n", sa->replay_state.oseq,
+ sa->replay_state.seq, sa->replay_state.bitmap);
+ }
+ }
+
+ nl_dump_line(p, "\tselector info: \n");
+ xfrmnl_sel_dump (sa->sel, p);
+
+ nl_dump_line(p, "\tHard: %d\n", sa->hard);
+
+ nl_dump(p, "\n");
+}
+
+static void xfrm_sa_dump_stats(struct nl_object *a, struct nl_dump_params *p)
+{
+ struct xfrmnl_sa* sa = (struct xfrmnl_sa*)a;
+
+ nl_dump_line(p, "\tstats: \n");
+ nl_dump_line(p, "\t\treplay window: %u replay: %u integrity failed: %u \n",
+ sa->stats.replay_window, sa->stats.replay, sa->stats.integrity_failed);
+
+ return;
+}
+
+static void xfrm_sa_dump_details(struct nl_object *a, struct nl_dump_params *p)
+{
+ xfrm_sa_dump_line(a, p);
+ xfrm_sa_dump_stats (a, p);
+}
+
+/**
+ * @name XFRM SA Object Allocation/Freeage
+ * @{
+ */
+
+struct xfrmnl_sa* xfrmnl_sa_alloc(void)
+{
+ return (struct xfrmnl_sa*) nl_object_alloc(&xfrm_sa_obj_ops);
+}
+
+void xfrmnl_sa_put(struct xfrmnl_sa* sa)
+{
+ nl_object_put((struct nl_object *) sa);
+}
+
+/** @} */
+
+/**
+ * @name SA Cache Managament
+ * @{
+ */
+
+/**
+ * Build a SA cache including all SAs currently configured in the kernel.
+ * @arg sock Netlink socket.
+ * @arg result Pointer to store resulting cache.
+ *
+ * Allocates a new SA cache, initializes it properly and updates it
+ * to include all SAs currently configured in the kernel.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int xfrmnl_sa_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
+{
+ return nl_cache_alloc_and_fill(&xfrmnl_sa_ops, sock, result);
+}
+
+/**
+ * Look up a SA by destination address, SPI, protocol
+ * @arg cache SA cache
+ * @arg daddr destination address of the SA
+ * @arg spi SPI
+ * @arg proto protocol
+ * @return sa handle or NULL if no match was found.
+ */
+struct xfrmnl_sa* xfrmnl_sa_get(struct nl_cache* cache, struct nl_addr* daddr,
+ unsigned int spi, unsigned int proto)
+{
+ struct xfrmnl_sa *sa;
+
+ //nl_list_for_each_entry(sa, &cache->c_items, ce_list) {
+ for (sa = (struct xfrmnl_sa*)nl_cache_get_first (cache);
+ sa != NULL;
+ sa = (struct xfrmnl_sa*)nl_cache_get_next ((struct nl_object*)sa))
+ {
+ if (sa->id.proto == proto &&
+ sa->id.spi == spi &&
+ !nl_addr_cmp(sa->id.daddr, daddr))
+ {
+ nl_object_get((struct nl_object *) sa);
+ return sa;
+ }
+
+ }
+
+ return NULL;
+}
+
+
+/** @} */
+
+
+static struct nla_policy xfrm_sa_policy[XFRMA_MAX+1] = {
+ [XFRMA_SA] = { .minlen = sizeof(struct xfrm_usersa_info)},
+ [XFRMA_ALG_AUTH_TRUNC] = { .minlen = sizeof(struct xfrm_algo_auth)},
+ [XFRMA_ALG_AEAD] = { .minlen = sizeof(struct xfrm_algo_aead) },
+ [XFRMA_ALG_AUTH] = { .minlen = sizeof(struct xfrm_algo) },
+ [XFRMA_ALG_CRYPT] = { .minlen = sizeof(struct xfrm_algo) },
+ [XFRMA_ALG_COMP] = { .minlen = sizeof(struct xfrm_algo) },
+ [XFRMA_ENCAP] = { .minlen = sizeof(struct xfrm_encap_tmpl) },
+ [XFRMA_TMPL] = { .minlen = sizeof(struct xfrm_user_tmpl) },
+ [XFRMA_SEC_CTX] = { .minlen = sizeof(struct xfrm_sec_ctx) },
+ [XFRMA_LTIME_VAL] = { .minlen = sizeof(struct xfrm_lifetime_cur) },
+ [XFRMA_REPLAY_VAL] = { .minlen = sizeof(struct xfrm_replay_state) },
+ [XFRMA_REPLAY_THRESH] = { .type = NLA_U32 },
+ [XFRMA_ETIMER_THRESH] = { .type = NLA_U32 },
+ [XFRMA_SRCADDR] = { .minlen = sizeof(xfrm_address_t) },
+ [XFRMA_COADDR] = { .minlen = sizeof(xfrm_address_t) },
+ [XFRMA_MARK] = { .minlen = sizeof(struct xfrm_mark) },
+ [XFRMA_TFCPAD] = { .type = NLA_U32 },
+ [XFRMA_REPLAY_ESN_VAL] = { .minlen = sizeof(struct xfrm_replay_state_esn) },
+};
+
+static int xfrm_sa_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+ struct xfrm_id sa_id;
+
+ memset (&sa_id, 0, sizeof (sa_id));
+ return nl_send_simple (h, XFRM_MSG_GETSA, NLM_F_DUMP,
+ &sa_id, sizeof (sa_id));
+}
+
+int xfrmnl_sa_parse(struct nlmsghdr *n, struct xfrmnl_sa **result)
+{
+ struct xfrmnl_sa* sa;
+ struct nlattr *tb[XFRMA_MAX + 1];
+ struct xfrm_usersa_info* sa_info;
+ struct xfrm_user_expire* ue;
+ int len, err;
+ struct nl_addr* addr;
+
+ sa = xfrmnl_sa_alloc();
+ if (!sa) {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+
+ sa->ce_msgtype = n->nlmsg_type;
+ if (n->nlmsg_type == XFRM_MSG_EXPIRE)
+ {
+ ue = nlmsg_data(n);
+ sa_info = &ue->state;
+ sa->hard = ue->hard;
+ sa->ce_mask |= XFRM_SA_ATTR_EXPIRE;
+ }
+ else if (n->nlmsg_type == XFRM_MSG_DELSA)
+ {
+ sa_info = (struct xfrm_usersa_info*)((char *)nlmsg_data(n) + sizeof (struct xfrm_usersa_id) + NLA_HDRLEN);
+ }
+ else
+ {
+ sa_info = nlmsg_data(n);
+ }
+
+ err = nlmsg_parse(n, sizeof(struct xfrm_usersa_info), tb, XFRMA_MAX, xfrm_sa_policy);
+ if (err < 0)
+ goto errout;
+
+ if (sa_info->sel.family == AF_INET)
+ addr = nl_addr_build (sa_info->sel.family, &sa_info->sel.daddr.a4, sizeof (sa_info->sel.daddr.a4));
+ else
+ addr = nl_addr_build (sa_info->sel.family, &sa_info->sel.daddr.a6, sizeof (sa_info->sel.daddr.a6));
+ nl_addr_set_prefixlen (addr, sa_info->sel.prefixlen_d);
+ xfrmnl_sel_set_daddr (sa->sel, addr);
+ xfrmnl_sel_set_prefixlen_d (sa->sel, sa_info->sel.prefixlen_d);
+
+ if (sa_info->sel.family == AF_INET)
+ addr = nl_addr_build (sa_info->sel.family, &sa_info->sel.saddr.a4, sizeof (sa_info->sel.saddr.a4));
+ else
+ addr = nl_addr_build (sa_info->sel.family, &sa_info->sel.saddr.a6, sizeof (sa_info->sel.saddr.a6));
+ nl_addr_set_prefixlen (addr, sa_info->sel.prefixlen_s);
+ xfrmnl_sel_set_saddr (sa->sel, addr);
+ xfrmnl_sel_set_prefixlen_s (sa->sel, sa_info->sel.prefixlen_s);
+
+ xfrmnl_sel_set_dport (sa->sel, ntohs(sa_info->sel.dport));
+ xfrmnl_sel_set_dportmask (sa->sel, ntohs(sa_info->sel.dport_mask));
+ xfrmnl_sel_set_sport (sa->sel, ntohs(sa_info->sel.sport));
+ xfrmnl_sel_set_sportmask (sa->sel, ntohs(sa_info->sel.sport_mask));
+ xfrmnl_sel_set_family (sa->sel, sa_info->sel.family);
+ xfrmnl_sel_set_proto (sa->sel, sa_info->sel.proto);
+ xfrmnl_sel_set_ifindex (sa->sel, sa_info->sel.ifindex);
+ xfrmnl_sel_set_userid (sa->sel, sa_info->sel.user);
+ sa->ce_mask |= XFRM_SA_ATTR_SEL;
+
+ if (sa_info->family == AF_INET)
+ sa->id.daddr = nl_addr_build (sa_info->family, &sa_info->id.daddr.a4, sizeof (sa_info->id.daddr.a4));
+ else
+ sa->id.daddr = nl_addr_build (sa_info->family, &sa_info->id.daddr.a6, sizeof (sa_info->id.daddr.a6));
+ sa->id.spi = ntohl(sa_info->id.spi);
+ sa->id.proto = sa_info->id.proto;
+ sa->ce_mask |= (XFRM_SA_ATTR_DADDR | XFRM_SA_ATTR_SPI | XFRM_SA_ATTR_PROTO);
+
+ if (sa_info->family == AF_INET)
+ sa->saddr = nl_addr_build (sa_info->family, &sa_info->saddr.a4, sizeof (sa_info->saddr.a4));
+ else
+ sa->saddr = nl_addr_build (sa_info->family, &sa_info->saddr.a6, sizeof (sa_info->saddr.a6));
+ sa->ce_mask |= XFRM_SA_ATTR_SADDR;
+
+ sa->lft->soft_byte_limit = sa_info->lft.soft_byte_limit;
+ sa->lft->hard_byte_limit = sa_info->lft.hard_byte_limit;
+ sa->lft->soft_packet_limit = sa_info->lft.soft_packet_limit;
+ sa->lft->hard_packet_limit = sa_info->lft.hard_packet_limit;
+ sa->lft->soft_add_expires_seconds = sa_info->lft.soft_add_expires_seconds;
+ sa->lft->hard_add_expires_seconds = sa_info->lft.hard_add_expires_seconds;
+ sa->lft->soft_use_expires_seconds = sa_info->lft.soft_use_expires_seconds;
+ sa->lft->hard_use_expires_seconds = sa_info->lft.hard_use_expires_seconds;
+ sa->ce_mask |= XFRM_SA_ATTR_LTIME_CFG;
+
+ sa->curlft.bytes = sa_info->curlft.bytes;
+ sa->curlft.packets = sa_info->curlft.packets;
+ sa->curlft.add_time = sa_info->curlft.add_time;
+ sa->curlft.use_time = sa_info->curlft.use_time;
+ sa->ce_mask |= XFRM_SA_ATTR_LTIME_CUR;
+
+ sa->stats.replay_window = sa_info->stats.replay_window;
+ sa->stats.replay = sa_info->stats.replay;
+ sa->stats.integrity_failed = sa_info->stats.integrity_failed;
+ sa->ce_mask |= XFRM_SA_ATTR_STATS;
+
+ sa->seq = sa_info->seq;
+ sa->reqid = sa_info->reqid;
+ sa->family = sa_info->family;
+ sa->mode = sa_info->mode;
+ sa->replay_window = sa_info->replay_window;
+ sa->flags = sa_info->flags;
+ sa->ce_mask |= (XFRM_SA_ATTR_SEQ | XFRM_SA_ATTR_REQID |
+ XFRM_SA_ATTR_FAMILY | XFRM_SA_ATTR_MODE |
+ XFRM_SA_ATTR_REPLAY_WIN | XFRM_SA_ATTR_FLAGS);
+
+ if (tb[XFRMA_ALG_AEAD]) {
+ struct xfrm_algo_aead* aead = nla_data(tb[XFRMA_ALG_AEAD]);
+ len = sizeof (struct xfrmnl_algo_aead) + ((aead->alg_key_len + 7) / 8);
+ if ((sa->aead = calloc (1, len)) == NULL)
+ {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+ memcpy ((void *)sa->aead, (void *)aead, len);
+ sa->ce_mask |= XFRM_SA_ATTR_ALG_AEAD;
+ }
+
+ if (tb[XFRMA_ALG_AUTH_TRUNC]) {
+ struct xfrm_algo_auth* auth = nla_data(tb[XFRMA_ALG_AUTH_TRUNC]);
+ len = sizeof (struct xfrmnl_algo_auth) + ((auth->alg_key_len + 7) / 8);
+ if ((sa->auth = calloc (1, len)) == NULL)
+ {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+ memcpy ((void *)sa->auth, (void *)auth, len);
+ sa->ce_mask |= XFRM_SA_ATTR_ALG_AUTH;
+ }
+
+ if (tb[XFRMA_ALG_AUTH] && !sa->auth) {
+ struct xfrm_algo* auth = nla_data(tb[XFRMA_ALG_AUTH]);
+ len = sizeof (struct xfrmnl_algo_auth) + ((auth->alg_key_len + 7) / 8);
+ if ((sa->auth = calloc (1, len)) == NULL)
+ {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+ strcpy(sa->auth->alg_name, auth->alg_name);
+ memcpy(sa->auth->alg_key, auth->alg_key, (auth->alg_key_len + 7) / 8);
+ sa->auth->alg_key_len = auth->alg_key_len;
+ sa->ce_mask |= XFRM_SA_ATTR_ALG_AUTH;
+ }
+
+ if (tb[XFRMA_ALG_CRYPT]) {
+ struct xfrm_algo* crypt = nla_data(tb[XFRMA_ALG_CRYPT]);
+ len = sizeof (struct xfrmnl_algo) + ((crypt->alg_key_len + 7) / 8);
+ if ((sa->crypt = calloc (1, len)) == NULL)
+ {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+ memcpy ((void *)sa->crypt, (void *)crypt, len);
+ sa->ce_mask |= XFRM_SA_ATTR_ALG_CRYPT;
+ }
+
+ if (tb[XFRMA_ALG_COMP]) {
+ struct xfrm_algo* comp = nla_data(tb[XFRMA_ALG_COMP]);
+ len = sizeof (struct xfrmnl_algo) + ((comp->alg_key_len + 7) / 8);
+ if ((sa->comp = calloc (1, len)) == NULL)
+ {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+ memcpy ((void *)sa->comp, (void *)comp, len);
+ sa->ce_mask |= XFRM_SA_ATTR_ALG_COMP;
+ }
+
+ if (tb[XFRMA_ENCAP]) {
+ struct xfrm_encap_tmpl* encap = nla_data(tb[XFRMA_ENCAP]);
+ len = sizeof (struct xfrmnl_encap_tmpl);
+ if ((sa->encap = calloc (1, len)) == NULL)
+ {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+ sa->encap->encap_type = encap->encap_type;
+ sa->encap->encap_sport = ntohs(encap->encap_sport);
+ sa->encap->encap_dport = ntohs(encap->encap_dport);
+ if (sa_info->family == AF_INET)
+ sa->encap->encap_oa = nl_addr_build (sa_info->family, &encap->encap_oa.a4, sizeof (encap->encap_oa.a4));
+ else
+ sa->encap->encap_oa = nl_addr_build (sa_info->family, &encap->encap_oa.a6, sizeof (encap->encap_oa.a6));
+ sa->ce_mask |= XFRM_SA_ATTR_ENCAP;
+ }
+
+ if (tb[XFRMA_TFCPAD]) {
+ sa->tfcpad = *(uint32_t*)nla_data(tb[XFRMA_TFCPAD]);
+ sa->ce_mask |= XFRM_SA_ATTR_TFCPAD;
+ }
+
+ if (tb[XFRMA_COADDR]) {
+ if (sa_info->family == AF_INET)
+ {
+ sa->coaddr = nl_addr_build(sa_info->family, nla_data(tb[XFRMA_COADDR]),
+ sizeof (uint32_t));
+ }
+ else
+ {
+ sa->coaddr = nl_addr_build(sa_info->family, nla_data(tb[XFRMA_COADDR]),
+ sizeof (uint32_t) * 4);
+ }
+ sa->ce_mask |= XFRM_SA_ATTR_COADDR;
+ }
+
+ if (tb[XFRMA_MARK]) {
+ struct xfrm_mark* m = nla_data(tb[XFRMA_MARK]);
+ sa->mark.m = m->m;
+ sa->mark.v = m->v;
+ sa->ce_mask |= XFRM_SA_ATTR_MARK;
+ }
+
+ if (tb[XFRMA_SEC_CTX]) {
+ struct xfrm_user_sec_ctx* sec_ctx = nla_data(tb[XFRMA_SEC_CTX]);
+ len = sizeof (struct xfrmnl_user_sec_ctx) + sec_ctx->ctx_len;
+ if ((sa->sec_ctx = calloc (1, len)) == NULL)
+ {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+ memcpy (sa->sec_ctx, sec_ctx, len);
+ sa->ce_mask |= XFRM_SA_ATTR_SECCTX;
+ }
+
+ if (tb[XFRMA_ETIMER_THRESH]) {
+ sa->replay_maxage = *(uint32_t*)nla_data(tb[XFRMA_ETIMER_THRESH]);
+ sa->ce_mask |= XFRM_SA_ATTR_REPLAY_MAXAGE;
+ }
+
+ if (tb[XFRMA_REPLAY_THRESH]) {
+ sa->replay_maxdiff = *(uint32_t*)nla_data(tb[XFRMA_REPLAY_THRESH]);
+ sa->ce_mask |= XFRM_SA_ATTR_REPLAY_MAXDIFF;
+ }
+
+ if (tb[XFRMA_REPLAY_ESN_VAL]) {
+ struct xfrm_replay_state_esn* esn = nla_data (tb[XFRMA_REPLAY_ESN_VAL]);
+ len = sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * esn->bmp_len);
+ if ((sa->replay_state_esn = calloc (1, len)) == NULL)
+ {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+ memcpy ((void *)sa->replay_state_esn, (void *)esn, len);
+ sa->ce_mask |= XFRM_SA_ATTR_REPLAY_STATE;
+ }
+ else if (tb[XFRMA_REPLAY_VAL])
+ {
+ struct xfrm_replay_state* replay_state = nla_data (tb[XFRMA_REPLAY_VAL]);
+ sa->replay_state.oseq = replay_state->oseq;
+ sa->replay_state.seq = replay_state->seq;
+ sa->replay_state.bitmap = replay_state->bitmap;
+ sa->ce_mask |= XFRM_SA_ATTR_REPLAY_STATE;
+ sa->replay_state_esn = NULL;
+ }
+
+ *result = sa;
+ return 0;
+
+errout:
+ xfrmnl_sa_put(sa);
+ return err;
+}
+
+static int xfrm_sa_update_cache (struct nl_cache *cache, struct nl_object *obj,
+ change_func_t change_cb, change_func_v2_t change_cb_v2,
+ void *data)
+{
+ struct nl_object* old_sa;
+ struct xfrmnl_sa* sa = (struct xfrmnl_sa*)obj;
+
+ if (nl_object_get_msgtype (obj) == XFRM_MSG_EXPIRE)
+ {
+ /* On hard expiry, the SA gets deleted too from the kernel state without any
+ * further delete event. On Expire message, we are only updating the cache with
+ * the SA object's new state. In absence of the explicit delete event, the cache will
+ * be out of sync with the kernel state. To get around this, expiry messages cache
+ * operations are handled here (installed with NL_ACT_UNSPEC action) instead of
+ * in Libnl Cache module. */
+
+ /* Do we already have this object in the cache? */
+ old_sa = nl_cache_search(cache, obj);
+ if (old_sa)
+ {
+ /* Found corresponding SA object in cache. Delete it */
+ nl_cache_remove (old_sa);
+ }
+
+ /* Handle the expiry event now */
+ if (sa->hard == 0)
+ {
+ /* Soft expiry event: Save the new object to the
+ * cache and notify application of the expiry event. */
+ nl_cache_move (cache, obj);
+
+ if (old_sa == NULL)
+ {
+ /* Application CB present, no previous instance of SA object present.
+ * Notify application CB as a NEW event */
+ if (change_cb_v2)
+ change_cb_v2(cache, NULL, obj, 0, NL_ACT_NEW, data);
+ else if (change_cb)
+ change_cb(cache, obj, NL_ACT_NEW, data);
+ }
+ else if (old_sa)
+ {
+ uint64_t diff = 0;
+ if (change_cb || change_cb_v2)
+ diff = nl_object_diff64(old_sa, obj);
+
+ /* Application CB present, a previous instance of SA object present.
+ * Notify application CB as a CHANGE1 event */
+ if (diff) {
+ if (change_cb_v2) {
+ change_cb_v2(cache, old_sa, obj, diff, NL_ACT_CHANGE, data);
+ } else if (change_cb)
+ change_cb(cache, obj, NL_ACT_CHANGE, data);
+ }
+ nl_object_put (old_sa);
+ }
+ }
+ else
+ {
+ /* Hard expiry event: Delete the object from the
+ * cache and notify application of the expiry event. */
+ if (change_cb_v2)
+ change_cb_v2(cache, obj, NULL, 0, NL_ACT_DEL, data);
+ else if (change_cb)
+ change_cb (cache, obj, NL_ACT_DEL, data);
+ nl_object_put (old_sa);
+ }
+
+ /* Done handling expire message */
+ return 0;
+ }
+ else
+ {
+ /* All other messages other than Expire, let the standard Libnl cache
+ * module handle it. */
+ if (change_cb_v2)
+ return nl_cache_include_v2(cache, obj, change_cb_v2, data);
+ else
+ return nl_cache_include (cache, obj, change_cb, data);
+ }
+}
+
+static int xfrm_sa_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+ struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+ struct xfrmnl_sa* sa;
+ int err;
+
+ if ((err = xfrmnl_sa_parse(n, &sa)) < 0)
+ return err;
+
+ err = pp->pp_cb((struct nl_object *) sa, pp);
+
+ xfrmnl_sa_put(sa);
+ return err;
+}
+
+/**
+ * @name XFRM SA Get
+ * @{
+ */
+
+int xfrmnl_sa_build_get_request(struct nl_addr* daddr, unsigned int spi, unsigned int protocol, unsigned int mark_v, unsigned int mark_m, struct nl_msg **result)
+{
+ struct nl_msg *msg;
+ struct xfrm_usersa_id sa_id;
+ struct xfrm_mark mark;
+
+ if (!daddr || !spi)
+ {
+ fprintf(stderr, "APPLICATION BUG: %s:%d:%s: A valid destination address, spi must be specified\n",
+ __FILE__, __LINE__, __func__);
+ assert(0);
+ return -NLE_MISSING_ATTR;
+ }
+
+ memset(&sa_id, 0, sizeof(sa_id));
+ memcpy (&sa_id.daddr, nl_addr_get_binary_addr (daddr), sizeof (uint8_t) * nl_addr_get_len (daddr));
+ sa_id.family = nl_addr_get_family (daddr);
+ sa_id.spi = htonl(spi);
+ sa_id.proto = protocol;
+
+ if (!(msg = nlmsg_alloc_simple(XFRM_MSG_GETSA, 0)))
+ return -NLE_NOMEM;
+
+ if (nlmsg_append(msg, &sa_id, sizeof(sa_id), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ if ((mark_m & mark_v) != 0)
+ {
+ memset(&mark, 0, sizeof(struct xfrm_mark));
+ mark.m = mark_m;
+ mark.v = mark_v;
+
+ NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrm_mark), &mark);
+ }
+
+ *result = msg;
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+}
+
+int xfrmnl_sa_get_kernel(struct nl_sock* sock, struct nl_addr* daddr, unsigned int spi, unsigned int protocol, unsigned int mark_v, unsigned int mark_m, struct xfrmnl_sa** result)
+{
+ struct nl_msg *msg = NULL;
+ struct nl_object *obj;
+ int err;
+
+ if ((err = xfrmnl_sa_build_get_request(daddr, spi, protocol, mark_m, mark_v, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto(sock, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ if ((err = nl_pickup(sock, &xfrm_sa_msg_parser, &obj)) < 0)
+ return err;
+
+ /* We have used xfrm_sa_msg_parser(), object is definitely a xfrm sa */
+ *result = (struct xfrmnl_sa *) obj;
+
+ /* If an object has been returned, we also need to wait for the ACK */
+ if (err == 0 && obj)
+ nl_wait_for_ack(sock);
+
+ return 0;
+}
+
+/** @} */
+
+static int build_xfrm_sa_message(struct xfrmnl_sa *tmpl, int cmd, int flags, struct nl_msg **result)
+{
+ struct nl_msg* msg;
+ struct xfrm_usersa_info sa_info;
+ uint32_t len;
+ struct nl_addr* addr;
+
+ if (!(tmpl->ce_mask & XFRM_SA_ATTR_DADDR) ||
+ !(tmpl->ce_mask & XFRM_SA_ATTR_SPI) ||
+ !(tmpl->ce_mask & XFRM_SA_ATTR_PROTO))
+ return -NLE_MISSING_ATTR;
+
+ memset ((void*)&sa_info, 0, sizeof (sa_info));
+ if (tmpl->ce_mask & XFRM_SA_ATTR_SEL)
+ {
+ addr = xfrmnl_sel_get_daddr (tmpl->sel);
+ memcpy ((void*)&sa_info.sel.daddr, (void*)nl_addr_get_binary_addr (addr), sizeof (uint8_t) * nl_addr_get_len (addr));
+ addr = xfrmnl_sel_get_saddr (tmpl->sel);
+ memcpy ((void*)&sa_info.sel.saddr, (void*)nl_addr_get_binary_addr (addr), sizeof (uint8_t) * nl_addr_get_len (addr));
+ sa_info.sel.dport = htons (xfrmnl_sel_get_dport (tmpl->sel));
+ sa_info.sel.dport_mask = htons (xfrmnl_sel_get_dportmask (tmpl->sel));
+ sa_info.sel.sport = htons (xfrmnl_sel_get_sport (tmpl->sel));
+ sa_info.sel.sport_mask = htons (xfrmnl_sel_get_sportmask (tmpl->sel));
+ sa_info.sel.family = xfrmnl_sel_get_family (tmpl->sel);
+ sa_info.sel.prefixlen_d = xfrmnl_sel_get_prefixlen_d (tmpl->sel);
+ sa_info.sel.prefixlen_s = xfrmnl_sel_get_prefixlen_s (tmpl->sel);
+ sa_info.sel.proto = xfrmnl_sel_get_proto (tmpl->sel);
+ sa_info.sel.ifindex = xfrmnl_sel_get_ifindex (tmpl->sel);
+ sa_info.sel.user = xfrmnl_sel_get_userid (tmpl->sel);
+ }
+
+ memcpy (&sa_info.id.daddr, nl_addr_get_binary_addr (tmpl->id.daddr), sizeof (uint8_t) * nl_addr_get_len (tmpl->id.daddr));
+ sa_info.id.spi = htonl(tmpl->id.spi);
+ sa_info.id.proto = tmpl->id.proto;
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_SADDR)
+ memcpy (&sa_info.saddr, nl_addr_get_binary_addr (tmpl->saddr), sizeof (uint8_t) * nl_addr_get_len (tmpl->saddr));
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_LTIME_CFG)
+ {
+ sa_info.lft.soft_byte_limit = xfrmnl_ltime_cfg_get_soft_bytelimit (tmpl->lft);
+ sa_info.lft.hard_byte_limit = xfrmnl_ltime_cfg_get_hard_bytelimit (tmpl->lft);
+ sa_info.lft.soft_packet_limit = xfrmnl_ltime_cfg_get_soft_packetlimit (tmpl->lft);
+ sa_info.lft.hard_packet_limit = xfrmnl_ltime_cfg_get_hard_packetlimit (tmpl->lft);
+ sa_info.lft.soft_add_expires_seconds = xfrmnl_ltime_cfg_get_soft_addexpires (tmpl->lft);
+ sa_info.lft.hard_add_expires_seconds = xfrmnl_ltime_cfg_get_hard_addexpires (tmpl->lft);
+ sa_info.lft.soft_use_expires_seconds = xfrmnl_ltime_cfg_get_soft_useexpires (tmpl->lft);
+ sa_info.lft.hard_use_expires_seconds = xfrmnl_ltime_cfg_get_hard_useexpires (tmpl->lft);
+ }
+
+ //Skip current lifetime: cur lifetime can be updated only via AE
+ //Skip stats: stats cant be updated
+ //Skip seq: seq cant be updated
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_REQID)
+ sa_info.reqid = tmpl->reqid;
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_FAMILY)
+ sa_info.family = tmpl->family;
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_MODE)
+ sa_info.mode = tmpl->mode;
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_REPLAY_WIN)
+ sa_info.replay_window = tmpl->replay_window;
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_FLAGS)
+ sa_info.flags = tmpl->flags;
+
+ msg = nlmsg_alloc_simple(cmd, flags);
+ if (!msg)
+ return -NLE_NOMEM;
+
+ if (nlmsg_append(msg, &sa_info, sizeof(sa_info), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_ALG_AEAD) {
+ len = sizeof (struct xfrm_algo_aead) + ((tmpl->aead->alg_key_len + 7) / 8);
+ NLA_PUT (msg, XFRMA_ALG_AEAD, len, tmpl->aead);
+ }
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_ALG_AUTH) {
+ /* kernel prefers XFRMA_ALG_AUTH_TRUNC over XFRMA_ALG_AUTH, so only
+ * one of the attributes needs to be present */
+ if (tmpl->auth->alg_trunc_len) {
+ len = sizeof (struct xfrm_algo_auth) + ((tmpl->auth->alg_key_len + 7) / 8);
+ NLA_PUT (msg, XFRMA_ALG_AUTH_TRUNC, len, tmpl->auth);
+ } else {
+ struct xfrm_algo *auth;
+
+ len = sizeof (struct xfrm_algo) + ((tmpl->auth->alg_key_len + 7) / 8);
+ auth = malloc(len);
+ if (!auth) {
+ nlmsg_free(msg);
+ return -NLE_NOMEM;
+ }
+
+ strncpy(auth->alg_name, tmpl->auth->alg_name, sizeof(auth->alg_name));
+ auth->alg_name[sizeof(auth->alg_name) - 1] = '\0';
+ auth->alg_key_len = tmpl->auth->alg_key_len;
+ memcpy(auth->alg_key, tmpl->auth->alg_key, (tmpl->auth->alg_key_len + 7) / 8);
+ if (nla_put(msg, XFRMA_ALG_AUTH, len, auth) < 0) {
+ free(auth);
+ goto nla_put_failure;
+ }
+ free(auth);
+ }
+ }
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_ALG_CRYPT) {
+ len = sizeof (struct xfrm_algo) + ((tmpl->crypt->alg_key_len + 7) / 8);
+ NLA_PUT (msg, XFRMA_ALG_CRYPT, len, tmpl->crypt);
+ }
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_ALG_COMP) {
+ len = sizeof (struct xfrm_algo) + ((tmpl->comp->alg_key_len + 7) / 8);
+ NLA_PUT (msg, XFRMA_ALG_COMP, len, tmpl->comp);
+ }
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_ENCAP) {
+ struct xfrm_encap_tmpl* encap_tmpl;
+ struct nlattr* encap_attr;
+
+ len = sizeof (struct xfrm_encap_tmpl);
+ encap_attr = nla_reserve(msg, XFRMA_ENCAP, len);
+ if (!encap_attr)
+ goto nla_put_failure;
+ encap_tmpl = nla_data (encap_attr);
+ encap_tmpl->encap_type = tmpl->encap->encap_type;
+ encap_tmpl->encap_sport = htons (tmpl->encap->encap_sport);
+ encap_tmpl->encap_dport = htons (tmpl->encap->encap_dport);
+ memcpy (&encap_tmpl->encap_oa, nl_addr_get_binary_addr (tmpl->encap->encap_oa), sizeof (uint8_t) * nl_addr_get_len (tmpl->encap->encap_oa));
+ }
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_TFCPAD) {
+ NLA_PUT_U32 (msg, XFRMA_TFCPAD, tmpl->tfcpad);
+ }
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_COADDR) {
+ NLA_PUT (msg, XFRMA_COADDR, sizeof (xfrm_address_t), tmpl->coaddr);
+ }
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_MARK) {
+ NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrm_mark), &tmpl->mark);
+ }
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_SECCTX) {
+ len = sizeof (struct xfrm_sec_ctx) + tmpl->sec_ctx->ctx_len;
+ NLA_PUT (msg, XFRMA_SEC_CTX, len, tmpl->sec_ctx);
+ }
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_REPLAY_MAXAGE) {
+ NLA_PUT_U32 (msg, XFRMA_ETIMER_THRESH, tmpl->replay_maxage);
+ }
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_REPLAY_MAXDIFF) {
+ NLA_PUT_U32 (msg, XFRMA_REPLAY_THRESH, tmpl->replay_maxdiff);
+ }
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_REPLAY_STATE) {
+ if (tmpl->replay_state_esn) {
+ len = sizeof (struct xfrm_replay_state_esn) + (sizeof (uint32_t) * tmpl->replay_state_esn->bmp_len);
+ NLA_PUT (msg, XFRMA_REPLAY_ESN_VAL, len, tmpl->replay_state_esn);
+ }
+ else {
+ NLA_PUT (msg, XFRMA_REPLAY_VAL, sizeof (struct xfrm_replay_state), &tmpl->replay_state);
+ }
+ }
+
+ *result = msg;
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+}
+
+/**
+ * @name XFRM SA Add
+ * @{
+ */
+
+int xfrmnl_sa_build_add_request(struct xfrmnl_sa* tmpl, int flags, struct nl_msg **result)
+{
+ return build_xfrm_sa_message (tmpl, XFRM_MSG_NEWSA, flags, result);
+}
+
+int xfrmnl_sa_add(struct nl_sock* sk, struct xfrmnl_sa* tmpl, int flags)
+{
+ int err;
+ struct nl_msg *msg;
+
+ if ((err = xfrmnl_sa_build_add_request(tmpl, flags, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ return nl_wait_for_ack(sk);
+}
+
+/**
+ * @name XFRM SA Update
+ * @{
+ */
+
+int xfrmnl_sa_build_update_request(struct xfrmnl_sa* tmpl, int flags, struct nl_msg **result)
+{
+ return build_xfrm_sa_message (tmpl, XFRM_MSG_UPDSA, flags, result);
+}
+
+int xfrmnl_sa_update(struct nl_sock* sk, struct xfrmnl_sa* tmpl, int flags)
+{
+ int err;
+ struct nl_msg *msg;
+
+ if ((err = xfrmnl_sa_build_update_request(tmpl, flags, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ return nl_wait_for_ack(sk);
+}
+
+/** @} */
+
+static int build_xfrm_sa_delete_message(struct xfrmnl_sa *tmpl, int cmd, int flags, struct nl_msg **result)
+{
+ struct nl_msg* msg;
+ struct xfrm_usersa_id sa_id;
+
+ if (!(tmpl->ce_mask & XFRM_SA_ATTR_DADDR) ||
+ !(tmpl->ce_mask & XFRM_SA_ATTR_SPI) ||
+ !(tmpl->ce_mask & XFRM_SA_ATTR_PROTO))
+ return -NLE_MISSING_ATTR;
+
+ memcpy (&sa_id.daddr, nl_addr_get_binary_addr (tmpl->id.daddr),
+ sizeof (uint8_t) * nl_addr_get_len (tmpl->id.daddr));
+ sa_id.family = nl_addr_get_family (tmpl->id.daddr);
+ sa_id.spi = htonl(tmpl->id.spi);
+ sa_id.proto = tmpl->id.proto;
+
+ msg = nlmsg_alloc_simple(cmd, flags);
+ if (!msg)
+ return -NLE_NOMEM;
+
+ if (nlmsg_append(msg, &sa_id, sizeof(sa_id), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ if (tmpl->ce_mask & XFRM_SA_ATTR_MARK) {
+ NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrm_mark), &tmpl->mark);
+ }
+
+ *result = msg;
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+}
+
+/**
+ * @name XFRM SA Delete
+ * @{
+ */
+
+int xfrmnl_sa_build_delete_request(struct xfrmnl_sa* tmpl, int flags, struct nl_msg **result)
+{
+ return build_xfrm_sa_delete_message (tmpl, XFRM_MSG_DELSA, flags, result);
+}
+
+int xfrmnl_sa_delete(struct nl_sock* sk, struct xfrmnl_sa* tmpl, int flags)
+{
+ int err;
+ struct nl_msg *msg;
+
+ if ((err = xfrmnl_sa_build_delete_request(tmpl, flags, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ return nl_wait_for_ack(sk);
+}
+
+/** @} */
+
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+struct xfrmnl_sel* xfrmnl_sa_get_sel (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_SEL)
+ return sa->sel;
+ else
+ return NULL;
+}
+
+int xfrmnl_sa_set_sel (struct xfrmnl_sa* sa, struct xfrmnl_sel* sel)
+{
+ /* Release any previously held selector object from the SA */
+ if (sa->sel)
+ xfrmnl_sel_put (sa->sel);
+
+ /* Increment ref count on new selector and save it in the SA */
+ xfrmnl_sel_get (sel);
+ sa->sel = sel;
+ sa->ce_mask |= XFRM_SA_ATTR_SEL;
+
+ return 0;
+}
+
+static inline int __assign_addr(struct xfrmnl_sa* sa, struct nl_addr **pos,
+ struct nl_addr *new, int flag, int nocheck)
+{
+ if (!nocheck)
+ {
+ if (sa->ce_mask & XFRM_SA_ATTR_FAMILY)
+ {
+ if (nl_addr_get_family (new) != sa->family)
+ return -NLE_AF_MISMATCH;
+ }
+ }
+
+ if (*pos)
+ nl_addr_put(*pos);
+
+ nl_addr_get(new);
+ *pos = new;
+
+ sa->ce_mask |= flag;
+
+ return 0;
+}
+
+
+struct nl_addr* xfrmnl_sa_get_daddr (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_DADDR)
+ return sa->id.daddr;
+ else
+ return NULL;
+}
+
+int xfrmnl_sa_set_daddr (struct xfrmnl_sa* sa, struct nl_addr* addr)
+{
+ return __assign_addr(sa, &sa->id.daddr, addr, XFRM_SA_ATTR_DADDR, 0);
+}
+
+int xfrmnl_sa_get_spi (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_SPI)
+ return sa->id.spi;
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_spi (struct xfrmnl_sa* sa, unsigned int spi)
+{
+ sa->id.spi = spi;
+ sa->ce_mask |= XFRM_SA_ATTR_SPI;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_proto (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_PROTO)
+ return sa->id.proto;
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_proto (struct xfrmnl_sa* sa, unsigned int protocol)
+{
+ sa->id.proto = protocol;
+ sa->ce_mask |= XFRM_SA_ATTR_PROTO;
+
+ return 0;
+}
+
+struct nl_addr* xfrmnl_sa_get_saddr (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_SADDR)
+ return sa->saddr;
+ else
+ return NULL;
+}
+
+int xfrmnl_sa_set_saddr (struct xfrmnl_sa* sa, struct nl_addr* addr)
+{
+ return __assign_addr(sa, &sa->saddr, addr, XFRM_SA_ATTR_SADDR, 1);
+}
+
+struct xfrmnl_ltime_cfg* xfrmnl_sa_get_lifetime_cfg (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_LTIME_CFG)
+ return sa->lft;
+ else
+ return NULL;
+}
+
+int xfrmnl_sa_set_lifetime_cfg (struct xfrmnl_sa* sa, struct xfrmnl_ltime_cfg* ltime)
+{
+ /* Release any previously held lifetime cfg object from the SA */
+ if (sa->lft)
+ xfrmnl_ltime_cfg_put (sa->lft);
+
+ /* Increment ref count on new lifetime object and save it in the SA */
+ xfrmnl_ltime_cfg_get (ltime);
+ sa->lft = ltime;
+ sa->ce_mask |= XFRM_SA_ATTR_LTIME_CFG;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_curlifetime (struct xfrmnl_sa* sa, unsigned long long int* curr_bytes,
+ unsigned long long int* curr_packets, unsigned long long int* curr_add_time, unsigned long long int* curr_use_time)
+{
+ if (sa == NULL || curr_bytes == NULL || curr_packets == NULL || curr_add_time == NULL || curr_use_time == NULL)
+ return -1;
+
+ if (sa->ce_mask & XFRM_SA_ATTR_LTIME_CUR)
+ {
+ *curr_bytes = sa->curlft.bytes;
+ *curr_packets = sa->curlft.packets;
+ *curr_add_time = sa->curlft.add_time;
+ *curr_use_time = sa->curlft.use_time;
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_stats (struct xfrmnl_sa* sa, unsigned long long int* replay_window,
+ unsigned long long int* replay, unsigned long long int* integrity_failed)
+{
+ if (sa == NULL || replay_window == NULL || replay == NULL || integrity_failed == NULL)
+ return -1;
+
+ if (sa->ce_mask & XFRM_SA_ATTR_STATS)
+ {
+ *replay_window = sa->stats.replay_window;
+ *replay = sa->stats.replay;
+ *integrity_failed = sa->stats.integrity_failed;
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_seq (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_SEQ)
+ return sa->seq;
+ else
+ return -1;
+}
+
+int xfrmnl_sa_get_reqid (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_REQID)
+ return sa->reqid;
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_reqid (struct xfrmnl_sa* sa, unsigned int reqid)
+{
+ sa->reqid = reqid;
+ sa->ce_mask |= XFRM_SA_ATTR_REQID;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_family (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_FAMILY)
+ return sa->family;
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_family (struct xfrmnl_sa* sa, unsigned int family)
+{
+ sa->family = family;
+ sa->ce_mask |= XFRM_SA_ATTR_FAMILY;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_mode (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_MODE)
+ return sa->mode;
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_mode (struct xfrmnl_sa* sa, unsigned int mode)
+{
+ sa->mode = mode;
+ sa->ce_mask |= XFRM_SA_ATTR_MODE;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_replay_window (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_REPLAY_WIN)
+ return sa->replay_window;
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_replay_window (struct xfrmnl_sa* sa, unsigned int replay_window)
+{
+ sa->replay_window = replay_window;
+ sa->ce_mask |= XFRM_SA_ATTR_REPLAY_WIN;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_flags (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_FLAGS)
+ return sa->flags;
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_flags (struct xfrmnl_sa* sa, unsigned int flags)
+{
+ sa->flags = flags;
+ sa->ce_mask |= XFRM_SA_ATTR_FLAGS;
+
+ return 0;
+}
+
+/**
+ * Get the aead-params
+ * @arg sa the xfrmnl_sa object
+ * @arg alg_name an optional output buffer for the algorithm name. Must be at least 64 bytes.
+ * @arg key_len an optional output value for the key length in bits.
+ * @arg icv_len an optional output value for the alt-icv-len.
+ * @arg key an optional buffer large enough for the key. It must contain at least
+ * ((@key_len + 7) / 8) bytes.
+ *
+ * Warning: you must ensure that @key is large enough. If you don't know the key_len before-hand,
+ * call xfrmnl_sa_get_aead_params() without @key argument to query only the required buffer size.
+ * This modified API is available in all versions of libnl3 that support the capability
+ * @def NL_CAPABILITY_XFRM_SA_KEY_SIZE (@see nl_has_capability for further information).
+ *
+ * @return 0 on success or a negative error code.
+ */
+int xfrmnl_sa_get_aead_params (struct xfrmnl_sa* sa, char* alg_name, unsigned int* key_len, unsigned int* icv_len, char* key)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_ALG_AEAD)
+ {
+ if (alg_name)
+ strcpy (alg_name, sa->aead->alg_name);
+ if (key_len)
+ *key_len = sa->aead->alg_key_len;
+ if (icv_len)
+ *icv_len = sa->aead->alg_icv_len;
+ if (key)
+ memcpy (key, sa->aead->alg_key, ((sa->aead->alg_key_len + 7)/8));
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+int xfrmnl_sa_set_aead_params (struct xfrmnl_sa* sa, const char* alg_name, unsigned int key_len, unsigned int icv_len, const char* key)
+{
+ _nl_auto_free struct xfrmnl_algo_aead *b = NULL;
+ size_t keysize = sizeof (uint8_t) * ((key_len + 7)/8);
+ uint32_t newlen = sizeof (struct xfrmnl_algo_aead) + keysize;
+
+ /* Free up the old key and allocate memory to hold new key */
+ if (strlen (alg_name) >= sizeof (sa->aead->alg_name))
+ return -1;
+ if (!(b = calloc (1, newlen)))
+ return -1;
+
+ strcpy (b->alg_name, alg_name);
+ b->alg_key_len = key_len;
+ b->alg_icv_len = icv_len;
+ memcpy (b->alg_key, key, keysize);
+
+ free (sa->aead);
+ sa->aead = _nl_steal_pointer (&b);
+ sa->ce_mask |= XFRM_SA_ATTR_ALG_AEAD;
+ return 0;
+}
+
+/**
+ * Get the auth-params
+ * @arg sa the xfrmnl_sa object
+ * @arg alg_name an optional output buffer for the algorithm name. Must be at least 64 bytes.
+ * @arg key_len an optional output value for the key length in bits.
+ * @arg trunc_len an optional output value for the alg-trunc-len.
+ * @arg key an optional buffer large enough for the key. It must contain at least
+ * ((@key_len + 7) / 8) bytes.
+ *
+ * Warning: you must ensure that @key is large enough. If you don't know the key_len before-hand,
+ * call xfrmnl_sa_get_auth_params() without @key argument to query only the required buffer size.
+ * This modified API is available in all versions of libnl3 that support the capability
+ * @def NL_CAPABILITY_XFRM_SA_KEY_SIZE (@see nl_has_capability for further information).
+ *
+ * @return 0 on success or a negative error code.
+ */
+int xfrmnl_sa_get_auth_params (struct xfrmnl_sa* sa, char* alg_name, unsigned int* key_len, unsigned int* trunc_len, char* key)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_ALG_AUTH)
+ {
+ if (alg_name)
+ strcpy (alg_name, sa->auth->alg_name);
+ if (key_len)
+ *key_len = sa->auth->alg_key_len;
+ if (trunc_len)
+ *trunc_len = sa->auth->alg_trunc_len;
+ if (key)
+ memcpy (key, sa->auth->alg_key, (sa->auth->alg_key_len + 7)/8);
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+int xfrmnl_sa_set_auth_params (struct xfrmnl_sa* sa, const char* alg_name, unsigned int key_len, unsigned int trunc_len, const char* key)
+{
+ _nl_auto_free struct xfrmnl_algo_auth *b = NULL;
+ size_t keysize = sizeof (uint8_t) * ((key_len + 7)/8);
+ uint32_t newlen = sizeof (struct xfrmnl_algo_auth) + keysize;
+
+ if (strlen (alg_name) >= sizeof (sa->auth->alg_name))
+ return -1;
+ if (!(b = calloc (1, newlen)))
+ return -1;
+
+ strcpy (b->alg_name, alg_name);
+ b->alg_key_len = key_len;
+ b->alg_trunc_len = trunc_len;
+ memcpy (b->alg_key, key, keysize);
+
+ free (sa->auth);
+ sa->auth = _nl_steal_pointer (&b);
+ sa->ce_mask |= XFRM_SA_ATTR_ALG_AUTH;
+ return 0;
+}
+
+/**
+ * Get the crypto-params
+ * @arg sa the xfrmnl_sa object
+ * @arg alg_name an optional output buffer for the algorithm name. Must be at least 64 bytes.
+ * @arg key_len an optional output value for the key length in bits.
+ * @arg key an optional buffer large enough for the key. It must contain at least
+ * ((@key_len + 7) / 8) bytes.
+ *
+ * Warning: you must ensure that @key is large enough. If you don't know the key_len before-hand,
+ * call xfrmnl_sa_get_crypto_params() without @key argument to query only the required buffer size.
+ * This modified API is available in all versions of libnl3 that support the capability
+ * @def NL_CAPABILITY_XFRM_SA_KEY_SIZE (@see nl_has_capability for further information).
+ *
+ * @return 0 on success or a negative error code.
+ */
+int xfrmnl_sa_get_crypto_params (struct xfrmnl_sa* sa, char* alg_name, unsigned int* key_len, char* key)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_ALG_CRYPT)
+ {
+ if (alg_name)
+ strcpy (alg_name, sa->crypt->alg_name);
+ if (key_len)
+ *key_len = sa->crypt->alg_key_len;
+ if (key)
+ memcpy (key, sa->crypt->alg_key, ((sa->crypt->alg_key_len + 7)/8));
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+int xfrmnl_sa_set_crypto_params (struct xfrmnl_sa* sa, const char* alg_name, unsigned int key_len, const char* key)
+{
+ _nl_auto_free struct xfrmnl_algo *b = NULL;
+ size_t keysize = sizeof (uint8_t) * ((key_len + 7)/8);
+ uint32_t newlen = sizeof (struct xfrmnl_algo) + keysize;
+
+ if (strlen (alg_name) >= sizeof (sa->crypt->alg_name))
+ return -1;
+ if (!(b = calloc (1, newlen)))
+ return -1;
+
+ strcpy (b->alg_name, alg_name);
+ b->alg_key_len = key_len;
+ memcpy (b->alg_key, key, keysize);
+
+ free(sa->crypt);
+ sa->crypt = _nl_steal_pointer(&b);
+ sa->ce_mask |= XFRM_SA_ATTR_ALG_CRYPT;
+ return 0;
+}
+
+/**
+ * Get the comp-params
+ * @arg sa the xfrmnl_sa object
+ * @arg alg_name an optional output buffer for the algorithm name. Must be at least 64 bytes.
+ * @arg key_len an optional output value for the key length in bits.
+ * @arg key an optional buffer large enough for the key. It must contain at least
+ * ((@key_len + 7) / 8) bytes.
+ *
+ * Warning: you must ensure that @key is large enough. If you don't know the key_len before-hand,
+ * call xfrmnl_sa_get_comp_params() without @key argument to query only the required buffer size.
+ * This modified API is available in all versions of libnl3 that support the capability
+ * @def NL_CAPABILITY_XFRM_SA_KEY_SIZE (@see nl_has_capability for further information).
+ *
+ * @return 0 on success or a negative error code.
+ */
+int xfrmnl_sa_get_comp_params (struct xfrmnl_sa* sa, char* alg_name, unsigned int* key_len, char* key)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_ALG_COMP)
+ {
+ if (alg_name)
+ strcpy (alg_name, sa->comp->alg_name);
+ if (key_len)
+ *key_len = sa->comp->alg_key_len;
+ if (key)
+ memcpy (key, sa->comp->alg_key, ((sa->comp->alg_key_len + 7)/8));
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+int xfrmnl_sa_set_comp_params (struct xfrmnl_sa* sa, const char* alg_name, unsigned int key_len, const char* key)
+{
+ _nl_auto_free struct xfrmnl_algo *b = NULL;
+ size_t keysize = sizeof (uint8_t) * ((key_len + 7)/8);
+ uint32_t newlen = sizeof (struct xfrmnl_algo) + keysize;
+
+ if (strlen (alg_name) >= sizeof (sa->comp->alg_name))
+ return -1;
+ if (!(b = calloc (1, newlen)))
+ return -1;
+
+ strcpy (b->alg_name, alg_name);
+ b->alg_key_len = key_len;
+ memcpy (b->alg_key, key, keysize);
+
+ free(sa->comp);
+ sa->comp = _nl_steal_pointer(&b);
+ sa->ce_mask |= XFRM_SA_ATTR_ALG_COMP;
+ return 0;
+}
+
+int xfrmnl_sa_get_encap_tmpl (struct xfrmnl_sa* sa, unsigned int* encap_type, unsigned int* encap_sport, unsigned int* encap_dport, struct nl_addr** encap_oa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_ENCAP)
+ {
+ *encap_type = sa->encap->encap_type;
+ *encap_sport = sa->encap->encap_sport;
+ *encap_dport = sa->encap->encap_dport;
+ *encap_oa = nl_addr_clone (sa->encap->encap_oa);
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+int xfrmnl_sa_set_encap_tmpl (struct xfrmnl_sa* sa, unsigned int encap_type, unsigned int encap_sport, unsigned int encap_dport, struct nl_addr* encap_oa)
+{
+ if (sa->encap) {
+ /* Free up the old encap OA */
+ if (sa->encap->encap_oa)
+ nl_addr_put(sa->encap->encap_oa);
+ memset(sa->encap, 0, sizeof (*sa->encap));
+ } else if ((sa->encap = calloc(1, sizeof(*sa->encap))) == NULL)
+ return -1;
+
+ /* Save the new info */
+ sa->encap->encap_type = encap_type;
+ sa->encap->encap_sport = encap_sport;
+ sa->encap->encap_dport = encap_dport;
+ nl_addr_get (encap_oa);
+ sa->encap->encap_oa = encap_oa;
+
+ sa->ce_mask |= XFRM_SA_ATTR_ENCAP;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_tfcpad (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_TFCPAD)
+ return sa->tfcpad;
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_tfcpad (struct xfrmnl_sa* sa, unsigned int tfcpad)
+{
+ sa->tfcpad = tfcpad;
+ sa->ce_mask |= XFRM_SA_ATTR_TFCPAD;
+
+ return 0;
+}
+
+struct nl_addr* xfrmnl_sa_get_coaddr (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_COADDR)
+ return sa->coaddr;
+ else
+ return NULL;
+}
+
+int xfrmnl_sa_set_coaddr (struct xfrmnl_sa* sa, struct nl_addr* coaddr)
+{
+ /* Free up the old coaddr */
+ if (sa->coaddr)
+ nl_addr_put (sa->coaddr);
+
+ /* Save the new info */
+ nl_addr_get (coaddr);
+ sa->coaddr = coaddr;
+
+ sa->ce_mask |= XFRM_SA_ATTR_COADDR;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_mark (struct xfrmnl_sa* sa, unsigned int* mark_mask, unsigned int* mark_value)
+{
+ if (mark_mask == NULL || mark_value == NULL)
+ return -1;
+
+ if (sa->ce_mask & XFRM_SA_ATTR_MARK)
+ {
+ *mark_mask = sa->mark.m;
+ *mark_value = sa->mark.v;
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_mark (struct xfrmnl_sa* sa, unsigned int value, unsigned int mask)
+{
+ sa->mark.v = value;
+ sa->mark.m = mask;
+ sa->ce_mask |= XFRM_SA_ATTR_MARK;
+
+ return 0;
+}
+
+/**
+ * Get the security context.
+ *
+ * @arg sa The xfrmnl_sa object.
+ * @arg doi An optional output value for the security context domain of interpretation.
+ * @arg alg An optional output value for the security context algorithm.
+ * @arg len An optional output value for the security context length, including the
+ * terminating null byte ('\0').
+ * @arg sid Unused parameter.
+ * @arg ctx_str An optional buffer large enough for the security context string. It must
+ * contain at least @len bytes.
+ *
+ * Warning: you must ensure that @ctx_str is large enough. If you don't know the length before-hand,
+ * call xfrmnl_sa_get_sec_ctx() without @ctx_str argument to query only the required buffer size.
+ * This modified API is available in all versions of libnl3 that support the capability
+ * @def NL_CAPABILITY_XFRM_SEC_CTX_LEN (@see nl_has_capability for further information).
+ *
+ * @return 0 on success or a negative error code.
+ */
+int xfrmnl_sa_get_sec_ctx (struct xfrmnl_sa* sa, unsigned int* doi, unsigned int* alg,
+ unsigned int* len, unsigned int* sid, char* ctx_str)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_SECCTX)
+ {
+ if (doi)
+ *doi = sa->sec_ctx->ctx_doi;
+ if (alg)
+ *alg = sa->sec_ctx->ctx_alg;
+ if (len)
+ *len = sa->sec_ctx->ctx_len;
+ if (ctx_str)
+ memcpy (ctx_str, sa->sec_ctx->ctx, sa->sec_ctx->ctx_len);
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+/**
+ * Set the security context.
+ *
+ * @arg sa The xfrmnl_sa object.
+ * @arg doi Parameter for the security context domain of interpretation.
+ * @arg alg Parameter for the security context algorithm.
+ * @arg len Parameter for the length of the security context string containing
+ * the terminating null byte ('\0').
+ * @arg sid Unused parameter.
+ * @arg ctx_str Buffer containing the security context string.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int xfrmnl_sa_set_sec_ctx (struct xfrmnl_sa* sa, unsigned int doi, unsigned int alg, unsigned int len,
+ unsigned int sid, const char* ctx_str)
+{
+ _nl_auto_free struct xfrmnl_user_sec_ctx *b = NULL;
+
+ if (!(b = calloc(1, sizeof (struct xfrmnl_user_sec_ctx) + 1 + len)))
+ return -1;
+
+ b->len = sizeof(struct xfrmnl_user_sec_ctx) + len;
+ b->exttype = XFRMA_SEC_CTX;
+ b->ctx_alg = alg;
+ b->ctx_doi = doi;
+ b->ctx_len = len;
+ memcpy (b->ctx, ctx_str, len);
+ b->ctx[len] = '\0';
+
+ free(sa->sec_ctx);
+ sa->sec_ctx = _nl_steal_pointer(&b);
+ sa->ce_mask |= XFRM_SA_ATTR_SECCTX;
+ return 0;
+}
+
+
+int xfrmnl_sa_get_replay_maxage (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_REPLAY_MAXAGE)
+ return sa->replay_maxage;
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_replay_maxage (struct xfrmnl_sa* sa, unsigned int replay_maxage)
+{
+ sa->replay_maxage = replay_maxage;
+ sa->ce_mask |= XFRM_SA_ATTR_REPLAY_MAXAGE;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_replay_maxdiff (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_REPLAY_MAXDIFF)
+ return sa->replay_maxdiff;
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_replay_maxdiff (struct xfrmnl_sa* sa, unsigned int replay_maxdiff)
+{
+ sa->replay_maxdiff = replay_maxdiff;
+ sa->ce_mask |= XFRM_SA_ATTR_REPLAY_MAXDIFF;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_replay_state (struct xfrmnl_sa* sa, unsigned int* oseq, unsigned int* seq, unsigned int* bmp)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_REPLAY_STATE)
+ {
+ if (sa->replay_state_esn == NULL)
+ {
+ *oseq = sa->replay_state.oseq;
+ *seq = sa->replay_state.seq;
+ *bmp = sa->replay_state.bitmap;
+
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_replay_state (struct xfrmnl_sa* sa, unsigned int oseq, unsigned int seq, unsigned int bitmap)
+{
+ sa->replay_state.oseq = oseq;
+ sa->replay_state.seq = seq;
+ sa->replay_state.bitmap = bitmap;
+ sa->ce_mask |= XFRM_SA_ATTR_REPLAY_STATE;
+
+ return 0;
+}
+
+int xfrmnl_sa_get_replay_state_esn (struct xfrmnl_sa* sa, unsigned int* oseq, unsigned int* seq, unsigned int* oseq_hi,
+ unsigned int* seq_hi, unsigned int* replay_window, unsigned int* bmp_len, unsigned int* bmp)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_REPLAY_STATE)
+ {
+ if (sa->replay_state_esn)
+ {
+ *oseq = sa->replay_state_esn->oseq;
+ *seq = sa->replay_state_esn->seq;
+ *oseq_hi= sa->replay_state_esn->oseq_hi;
+ *seq_hi = sa->replay_state_esn->seq_hi;
+ *replay_window = sa->replay_state_esn->replay_window;
+ *bmp_len = sa->replay_state_esn->bmp_len; // In number of 32 bit words
+ memcpy (bmp, sa->replay_state_esn->bmp, sa->replay_state_esn->bmp_len * sizeof (uint32_t));
+
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else
+ return -1;
+}
+
+int xfrmnl_sa_set_replay_state_esn (struct xfrmnl_sa* sa, unsigned int oseq, unsigned int seq,
+ unsigned int oseq_hi, unsigned int seq_hi, unsigned int replay_window,
+ unsigned int bmp_len, unsigned int* bmp)
+{
+ _nl_auto_free struct xfrmnl_replay_state_esn *b = NULL;
+
+ if (!(b = calloc (1, sizeof (struct xfrmnl_replay_state_esn) + (sizeof (uint32_t) * bmp_len))))
+ return -1;
+
+ b->oseq = oseq;
+ b->seq = seq;
+ b->oseq_hi = oseq_hi;
+ b->seq_hi = seq_hi;
+ b->replay_window = replay_window;
+ b->bmp_len = bmp_len; // In number of 32 bit words
+ memcpy (b->bmp, bmp, bmp_len * sizeof (uint32_t));
+
+ free(sa->replay_state_esn);
+ sa->replay_state_esn = _nl_steal_pointer(&b);
+ sa->ce_mask |= XFRM_SA_ATTR_REPLAY_STATE;
+ return 0;
+}
+
+
+int xfrmnl_sa_is_hardexpiry_reached (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_EXPIRE)
+ return (sa->hard > 0 ? 1: 0);
+ else
+ return 0;
+}
+
+int xfrmnl_sa_is_expiry_reached (struct xfrmnl_sa* sa)
+{
+ if (sa->ce_mask & XFRM_SA_ATTR_EXPIRE)
+ return 1;
+ else
+ return 0;
+}
+
+/** @} */
+
+static struct nl_object_ops xfrm_sa_obj_ops = {
+ .oo_name = "xfrm/sa",
+ .oo_size = sizeof(struct xfrmnl_sa),
+ .oo_constructor = xfrm_sa_alloc_data,
+ .oo_free_data = xfrm_sa_free_data,
+ .oo_clone = xfrm_sa_clone,
+ .oo_dump = {
+ [NL_DUMP_LINE] = xfrm_sa_dump_line,
+ [NL_DUMP_DETAILS] = xfrm_sa_dump_details,
+ [NL_DUMP_STATS] = xfrm_sa_dump_stats,
+ },
+ .oo_compare = xfrm_sa_compare,
+ .oo_attrs2str = xfrm_sa_attrs2str,
+ .oo_id_attrs = (XFRM_SA_ATTR_DADDR | XFRM_SA_ATTR_SPI | XFRM_SA_ATTR_PROTO),
+};
+
+static struct nl_af_group xfrm_sa_groups[] = {
+ { AF_UNSPEC, XFRMNLGRP_SA },
+ { AF_UNSPEC, XFRMNLGRP_EXPIRE },
+ { END_OF_GROUP_LIST },
+};
+
+static struct nl_cache_ops xfrmnl_sa_ops = {
+ .co_name = "xfrm/sa",
+ .co_hdrsize = sizeof(struct xfrm_usersa_info),
+ .co_msgtypes = {
+ { XFRM_MSG_NEWSA, NL_ACT_NEW, "new" },
+ { XFRM_MSG_DELSA, NL_ACT_DEL, "del" },
+ { XFRM_MSG_GETSA, NL_ACT_GET, "get" },
+ { XFRM_MSG_EXPIRE, NL_ACT_UNSPEC, "expire"},
+ { XFRM_MSG_UPDSA, NL_ACT_NEW, "update"},
+ END_OF_MSGTYPES_LIST,
+ },
+ .co_protocol = NETLINK_XFRM,
+ .co_groups = xfrm_sa_groups,
+ .co_request_update = xfrm_sa_request_update,
+ .co_msg_parser = xfrm_sa_msg_parser,
+ .co_obj_ops = &xfrm_sa_obj_ops,
+ .co_include_event = &xfrm_sa_update_cache
+};
+
+/**
+ * @name XFRM SA Cache Managament
+ * @{
+ */
+
+static void __attribute__ ((constructor)) xfrm_sa_init(void)
+{
+ nl_cache_mngt_register(&xfrmnl_sa_ops);
+}
+
+static void __attribute__ ((destructor)) xfrm_sa_exit(void)
+{
+ nl_cache_mngt_unregister(&xfrmnl_sa_ops);
+}
+
+/** @} */
diff --git a/lib/xfrm/selector.c b/lib/xfrm/selector.c
new file mode 100644
index 00000000..04d30c35
--- /dev/null
+++ b/lib/xfrm/selector.c
@@ -0,0 +1,353 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**
+ * @ingroup xfrmnl
+ * @defgroup XFRM Address Selector
+ *
+ * Abstract data type representing XFRM SA/SP selector properties
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/xfrm/selector.h>
+ * ~~~~
+ */
+
+#include <netlink/xfrm/selector.h>
+#include <netlink-private/netlink.h>
+
+static void sel_destroy(struct xfrmnl_sel* sel)
+{
+ if (!sel)
+ return;
+
+ if (sel->refcnt != 1)
+ {
+ fprintf(stderr, "BUG: %s:%d\n", __FILE__, __LINE__);
+ assert(0);
+ }
+
+ nl_addr_put (sel->daddr);
+ nl_addr_put (sel->saddr);
+ free(sel);
+}
+
+/**
+ * @name Creating Selector
+ * @{
+ */
+
+/**
+ * Allocate new selector object.
+ * @return Newly allocated selector object or NULL
+ */
+struct xfrmnl_sel* xfrmnl_sel_alloc()
+{
+ struct xfrmnl_sel* sel;
+
+ sel = calloc(1, sizeof(struct xfrmnl_sel));
+ if (!sel)
+ return NULL;
+
+ sel->refcnt = 1;
+
+ return sel;
+}
+
+/**
+ * Clone existing selector object.
+ * @arg sel Selector object.
+ * @return Newly allocated selector object being a duplicate of the
+ * specified selector object or NULL if a failure occured.
+ */
+struct xfrmnl_sel* xfrmnl_sel_clone(struct xfrmnl_sel* sel)
+{
+ struct xfrmnl_sel* new;
+
+ new = xfrmnl_sel_alloc();
+ if (!new)
+ return NULL;
+
+ memcpy(new, sel, sizeof(struct xfrmnl_sel));
+ new->daddr = nl_addr_clone(sel->daddr);
+ new->saddr = nl_addr_clone(sel->saddr);
+
+ return new;
+}
+
+/** @} */
+
+/**
+ * @name Managing Usage References
+ * @{
+ */
+
+struct xfrmnl_sel* xfrmnl_sel_get(struct xfrmnl_sel* sel)
+{
+ sel->refcnt++;
+
+ return sel;
+}
+
+void xfrmnl_sel_put(struct xfrmnl_sel* sel)
+{
+ if (!sel)
+ return;
+
+ if (sel->refcnt == 1)
+ sel_destroy(sel);
+ else
+ sel->refcnt--;
+}
+
+/**
+ * Check whether an selector object is shared.
+ * @arg addr Selector object.
+ * @return Non-zero if the selector object is shared, otherwise 0.
+ */
+int xfrmnl_sel_shared(struct xfrmnl_sel* sel)
+{
+ return sel->refcnt > 1;
+}
+
+/** @} */
+
+/**
+ * @name Miscellaneous
+ * @{
+ */
+
+/**
+ * Compares two selector objects.
+ * @arg a A selector object.
+ * @arg b Another selector object.
+ *
+ * @return Non zero if difference is found, 0 otherwise if both
+ * the objects are identical.
+ */
+int xfrmnl_sel_cmp(struct xfrmnl_sel* a, struct xfrmnl_sel* b)
+{
+ /* Check for any differences */
+ if ((nl_addr_cmp_prefix (a->daddr, b->daddr) != 0) ||
+ (nl_addr_cmp_prefix (a->saddr, b->saddr) != 0) ||
+ ((a->sport & a->sport_mask) != (b->sport & b->sport_mask)) ||
+ ((a->dport & a->dport_mask) != (b->dport & b->dport_mask)) ||
+ (a->family != b->family) ||
+ (a->proto && (a->proto != b->proto)) ||
+ (a->ifindex && a->ifindex != b->ifindex) ||
+ (a->user != b->user))
+ return 1;
+
+ /* The objects are identical */
+ return 0;
+}
+
+void xfrmnl_sel_dump(struct xfrmnl_sel* sel, struct nl_dump_params *p)
+{
+ char dst[INET6_ADDRSTRLEN+5], src[INET6_ADDRSTRLEN+5];
+ char buf [128];
+
+ nl_dump_line(p, "\t\tsrc %s dst %s family: %s\n", nl_addr2str(sel->saddr, src, sizeof(src)),
+ nl_addr2str (sel->daddr, dst, sizeof (dst)), nl_af2str (sel->family, buf, 128));
+ nl_dump_line (p, "\t\tsrc port/mask: %d/%d dst port/mask: %d/%d\n",
+ sel->dport, sel->dport_mask, sel->sport, sel->sport_mask);
+ nl_dump_line (p, "\t\tprotocol: %s ifindex: %u user: %u\n",
+ nl_ip_proto2str (sel->proto, buf, sizeof(buf)), sel->ifindex, sel->user);
+
+ return;
+}
+
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+struct nl_addr* xfrmnl_sel_get_daddr (struct xfrmnl_sel* sel)
+{
+ return sel->daddr;
+}
+
+int xfrmnl_sel_set_daddr (struct xfrmnl_sel* sel, struct nl_addr* addr)
+{
+ /* Increment reference counter on this to keep this address
+ * object around while selector in use */
+ nl_addr_get(addr);
+
+ sel->daddr = addr;
+
+ return 0;
+}
+
+struct nl_addr* xfrmnl_sel_get_saddr (struct xfrmnl_sel* sel)
+{
+ return sel->saddr;
+}
+
+int xfrmnl_sel_set_saddr (struct xfrmnl_sel* sel, struct nl_addr* addr)
+{
+ /* Increment reference counter on this to keep this address
+ * object around while selector in use */
+ nl_addr_get(addr);
+
+ sel->saddr = addr;
+
+ return 0;
+}
+
+int xfrmnl_sel_get_dport (struct xfrmnl_sel* sel)
+{
+ return sel->dport;
+}
+
+int xfrmnl_sel_set_dport (struct xfrmnl_sel* sel, unsigned int dport)
+{
+ sel->dport = dport;
+
+ return 0;
+}
+
+int xfrmnl_sel_get_dportmask (struct xfrmnl_sel* sel)
+{
+ return sel->dport_mask;
+}
+
+int xfrmnl_sel_set_dportmask (struct xfrmnl_sel* sel, unsigned int dport_mask)
+{
+ sel->dport_mask = dport_mask;
+
+ return 0;
+}
+
+int xfrmnl_sel_get_sport (struct xfrmnl_sel* sel)
+{
+ return sel->sport;
+}
+
+int xfrmnl_sel_set_sport (struct xfrmnl_sel* sel, unsigned int sport)
+{
+ sel->sport = sport;
+
+ return 0;
+}
+
+int xfrmnl_sel_get_sportmask (struct xfrmnl_sel* sel)
+{
+ return sel->sport_mask;
+}
+
+int xfrmnl_sel_set_sportmask (struct xfrmnl_sel* sel, unsigned int sport_mask)
+{
+ sel->sport_mask = sport_mask;
+
+ return 0;
+}
+
+int xfrmnl_sel_get_family(struct xfrmnl_sel *sel)
+{
+ return sel->family;
+}
+
+int xfrmnl_sel_set_family(struct xfrmnl_sel *sel, unsigned int family)
+{
+ sel->family = family;
+
+ return 0;
+}
+
+int xfrmnl_sel_get_prefixlen_d (struct xfrmnl_sel* sel)
+{
+ return sel->prefixlen_d;
+}
+
+int xfrmnl_sel_set_prefixlen_d (struct xfrmnl_sel* sel, unsigned int prefixlen)
+{
+ sel->prefixlen_d = prefixlen;
+
+ return 0;
+}
+
+int xfrmnl_sel_get_prefixlen_s (struct xfrmnl_sel* sel)
+{
+ return sel->prefixlen_s;
+}
+
+int xfrmnl_sel_set_prefixlen_s (struct xfrmnl_sel* sel, unsigned int prefixlen)
+{
+ sel->prefixlen_s = prefixlen;
+
+ return 0;
+}
+
+int xfrmnl_sel_get_proto (struct xfrmnl_sel* sel)
+{
+ return sel->proto;
+}
+
+int xfrmnl_sel_set_proto (struct xfrmnl_sel* sel, unsigned int protocol)
+{
+ sel->proto = protocol;
+
+ return 0;
+}
+
+int xfrmnl_sel_get_ifindex (struct xfrmnl_sel* sel)
+{
+ return sel->ifindex;
+}
+
+int xfrmnl_sel_set_ifindex (struct xfrmnl_sel* sel, unsigned int ifindex)
+{
+ sel->ifindex = ifindex;
+
+ return 0;
+}
+
+int xfrmnl_sel_get_userid (struct xfrmnl_sel* sel)
+{
+ return sel->user;
+}
+
+int xfrmnl_sel_set_userid (struct xfrmnl_sel* sel, unsigned int userid)
+{
+ sel->user = userid;
+ return 0;
+}
+
+
+/** @} */
diff --git a/lib/xfrm/sp.c b/lib/xfrm/sp.c
new file mode 100644
index 00000000..99b6a4ce
--- /dev/null
+++ b/lib/xfrm/sp.c
@@ -0,0 +1,1436 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**
+ * @ingroup xfrmnl
+ * @defgroup sp Security Policy
+ * @brief
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/object.h>
+#include <netlink/xfrm/selector.h>
+#include <netlink/xfrm/lifetime.h>
+#include <netlink/xfrm/template.h>
+#include <netlink/xfrm/sp.h>
+
+/** @cond SKIP */
+#define XFRM_SP_ATTR_SEL 0x01
+#define XFRM_SP_ATTR_LTIME_CFG 0x02
+#define XFRM_SP_ATTR_LTIME_CUR 0x04
+#define XFRM_SP_ATTR_PRIO 0x08
+#define XFRM_SP_ATTR_INDEX 0x10
+#define XFRM_SP_ATTR_DIR 0x20
+#define XFRM_SP_ATTR_ACTION 0x40
+#define XFRM_SP_ATTR_FLAGS 0x80
+#define XFRM_SP_ATTR_SHARE 0x100
+#define XFRM_SP_ATTR_POLTYPE 0x200
+#define XFRM_SP_ATTR_SECCTX 0x400
+#define XFRM_SP_ATTR_TMPL 0x800
+#define XFRM_SP_ATTR_MARK 0x1000
+
+static struct nl_cache_ops xfrmnl_sp_ops;
+static struct nl_object_ops xfrm_sp_obj_ops;
+/** @endcond */
+
+static void xfrm_sp_alloc_data(struct nl_object *c)
+{
+ struct xfrmnl_sp* sp = nl_object_priv (c);
+
+ if ((sp->sel = xfrmnl_sel_alloc ()) == NULL)
+ return;
+
+ if ((sp->lft = xfrmnl_ltime_cfg_alloc ()) == NULL)
+ return;
+
+ nl_init_list_head(&sp->usertmpl_list);
+
+ return;
+}
+
+static void xfrm_sp_free_data(struct nl_object *c)
+{
+ struct xfrmnl_sp* sp = nl_object_priv (c);
+ struct xfrmnl_user_tmpl *utmpl, *tmp;
+
+ if (sp == NULL)
+ return;
+
+ xfrmnl_sel_put (sp->sel);
+ xfrmnl_ltime_cfg_put (sp->lft);
+
+ if(sp->sec_ctx)
+ {
+ free (sp->sec_ctx);
+ }
+
+ nl_list_for_each_entry_safe(utmpl, tmp, &sp->usertmpl_list, utmpl_list) {
+ xfrmnl_sp_remove_usertemplate (sp, utmpl);
+ xfrmnl_user_tmpl_free (utmpl);
+ }
+}
+
+static int xfrm_sp_clone(struct nl_object *_dst, struct nl_object *_src)
+{
+ struct xfrmnl_sp* dst = nl_object_priv(_dst);
+ struct xfrmnl_sp* src = nl_object_priv(_src);
+ uint32_t len = 0;
+ struct xfrmnl_user_tmpl *utmpl, *new;
+
+ if (src->sel)
+ if ((dst->sel = xfrmnl_sel_clone (src->sel)) == NULL)
+ return -NLE_NOMEM;
+
+ if (src->lft)
+ if ((dst->lft = xfrmnl_ltime_cfg_clone (src->lft)) == NULL)
+ return -NLE_NOMEM;
+
+ if(src->sec_ctx)
+ {
+ len = sizeof (struct xfrmnl_user_sec_ctx) + src->sec_ctx->ctx_len;
+ if ((dst->sec_ctx = calloc (1, len)) == NULL)
+ return -NLE_NOMEM;
+ memcpy ((void *)dst->sec_ctx, (void *)src->sec_ctx, len);
+ }
+
+ nl_init_list_head(&dst->usertmpl_list);
+ nl_list_for_each_entry(utmpl, &src->usertmpl_list, utmpl_list) {
+ new = xfrmnl_user_tmpl_clone (utmpl);
+ if (!new)
+ return -NLE_NOMEM;
+
+ xfrmnl_sp_add_usertemplate(dst, new);
+ }
+
+ return 0;
+}
+
+static uint64_t xfrm_sp_compare(struct nl_object *_a, struct nl_object *_b,
+ uint64_t attrs, int flags)
+{
+ struct xfrmnl_sp* a = (struct xfrmnl_sp *) _a;
+ struct xfrmnl_sp* b = (struct xfrmnl_sp *) _b;
+ struct xfrmnl_user_tmpl *tmpl_a, *tmpl_b;
+ uint64_t diff = 0;
+
+#define XFRM_SP_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, XFRM_SP_ATTR_##ATTR, a, b, EXPR)
+ diff |= XFRM_SP_DIFF(SEL, xfrmnl_sel_cmp(a->sel, b->sel));
+ diff |= XFRM_SP_DIFF(LTIME_CFG, xfrmnl_ltime_cfg_cmp(a->lft, b->lft));
+ diff |= XFRM_SP_DIFF(PRIO, a->priority != b->priority);
+ diff |= XFRM_SP_DIFF(INDEX, a->index != b->index);
+ diff |= XFRM_SP_DIFF(DIR, a->dir != b->dir);
+ diff |= XFRM_SP_DIFF(ACTION, a->action != b->action);
+ diff |= XFRM_SP_DIFF(FLAGS, a->flags != b->flags);
+ diff |= XFRM_SP_DIFF(SHARE, a->share != b->share);
+ diff |= XFRM_SP_DIFF(SECCTX,((a->sec_ctx->len != b->sec_ctx->len) ||
+ (a->sec_ctx->exttype != b->sec_ctx->exttype) ||
+ (a->sec_ctx->ctx_alg != b->sec_ctx->ctx_alg) ||
+ (a->sec_ctx->ctx_doi != b->sec_ctx->ctx_doi) ||
+ (a->sec_ctx->ctx_len != b->sec_ctx->ctx_len) ||
+ strcmp(a->sec_ctx->ctx, b->sec_ctx->ctx)));
+ diff |= XFRM_SP_DIFF(POLTYPE,(a->uptype.type != b->uptype.type));
+ diff |= XFRM_SP_DIFF(TMPL,(a->nr_user_tmpl != b->nr_user_tmpl));
+ diff |= XFRM_SP_DIFF(MARK,(a->mark.m != b->mark.m) ||
+ (a->mark.v != b->mark.v));
+
+ /* Compare the templates */
+ nl_list_for_each_entry(tmpl_b, &b->usertmpl_list, utmpl_list)
+ nl_list_for_each_entry(tmpl_a, &a->usertmpl_list, utmpl_list)
+ diff |= xfrmnl_user_tmpl_cmp (tmpl_a, tmpl_b);
+#undef XFRM_SP_DIFF
+
+ return diff;
+}
+
+/**
+ * @name XFRM SP Attribute Translations
+ * @{
+ */
+static const struct trans_tbl sp_attrs[] = {
+ __ADD(XFRM_SP_ATTR_SEL, selector),
+ __ADD(XFRM_SP_ATTR_LTIME_CFG, lifetime_cfg),
+ __ADD(XFRM_SP_ATTR_LTIME_CUR, lifetime_cur),
+ __ADD(XFRM_SP_ATTR_PRIO, priority),
+ __ADD(XFRM_SP_ATTR_INDEX, index),
+ __ADD(XFRM_SP_ATTR_DIR, direction),
+ __ADD(XFRM_SP_ATTR_ACTION, action),
+ __ADD(XFRM_SP_ATTR_FLAGS, flags),
+ __ADD(XFRM_SP_ATTR_SHARE, share),
+ __ADD(XFRM_SP_ATTR_POLTYPE, policy_type),
+ __ADD(XFRM_SP_ATTR_SECCTX, security_context),
+ __ADD(XFRM_SP_ATTR_TMPL, user_template),
+ __ADD(XFRM_SP_ATTR_MARK, mark),
+};
+
+static char* xfrm_sp_attrs2str(int attrs, char *buf, size_t len)
+{
+ return __flags2str (attrs, buf, len, sp_attrs, ARRAY_SIZE(sp_attrs));
+}
+/** @} */
+
+/**
+ * @name XFRM SP Action Translations
+ * @{
+ */
+static const struct trans_tbl sa_actions[] = {
+ __ADD(XFRM_POLICY_ALLOW, allow),
+ __ADD(XFRM_POLICY_BLOCK, block),
+};
+
+char* xfrmnl_sp_action2str(int action, char *buf, size_t len)
+{
+ return __type2str (action, buf, len, sa_actions, ARRAY_SIZE(sa_actions));
+}
+
+int xfrmnl_sp_str2action(const char *name)
+{
+ return __str2type (name, sa_actions, ARRAY_SIZE(sa_actions));
+}
+/** @} */
+
+/**
+ * @name XFRM SP Flags Translations
+ * @{
+ */
+static const struct trans_tbl sp_flags[] = {
+ __ADD(XFRM_POLICY_LOCALOK, allow policy override by user),
+ __ADD(XFRM_POLICY_ICMP, auto include ICMP in policy),
+};
+
+char* xfrmnl_sp_flags2str(int flags, char *buf, size_t len)
+{
+ return __flags2str (flags, buf, len, sp_flags, ARRAY_SIZE(sp_flags));
+}
+
+int xfrmnl_sp_str2flag(const char *name)
+{
+ return __str2flags(name, sp_flags, ARRAY_SIZE(sp_flags));
+}
+/** @} */
+
+/**
+ * @name XFRM SP Type Translations
+ * @{
+ */
+static const struct trans_tbl sp_types[] = {
+ __ADD(XFRM_POLICY_TYPE_MAIN, main),
+ __ADD(XFRM_POLICY_TYPE_SUB, sub),
+ __ADD(XFRM_POLICY_TYPE_MAX, max),
+ __ADD(XFRM_POLICY_TYPE_ANY, any),
+};
+
+char* xfrmnl_sp_type2str(int type, char *buf, size_t len)
+{
+ return __type2str(type, buf, len, sp_types, ARRAY_SIZE(sp_types));
+}
+
+int xfrmnl_sp_str2type(const char *name)
+{
+ return __str2type(name, sp_types, ARRAY_SIZE(sp_types));
+}
+/** @} */
+
+/**
+ * @name XFRM SP Direction Translations
+ * @{
+ */
+static const struct trans_tbl sp_dir[] = {
+ __ADD(XFRM_POLICY_IN, in),
+ __ADD(XFRM_POLICY_OUT, out),
+ __ADD(XFRM_POLICY_FWD, fwd),
+ __ADD(XFRM_POLICY_MASK, mask),
+};
+
+char* xfrmnl_sp_dir2str(int dir, char *buf, size_t len)
+{
+ return __type2str (dir, buf, len, sp_dir, ARRAY_SIZE(sp_dir));
+}
+
+int xfrmnl_sp_str2dir(const char *name)
+{
+ return __str2type (name, sp_dir, ARRAY_SIZE(sp_dir));
+}
+
+int xfrmnl_sp_index2dir (unsigned int index)
+{
+ return index & 0x7;
+}
+/** @} */
+
+/**
+ * @name XFRM SP Share Translations
+ * @{
+ */
+static const struct trans_tbl sp_share[] = {
+ __ADD(XFRM_SHARE_ANY, any),
+ __ADD(XFRM_SHARE_SESSION, session),
+ __ADD(XFRM_SHARE_USER, user),
+ __ADD(XFRM_SHARE_UNIQUE, unique),
+};
+
+char* xfrmnl_sp_share2str(int share, char *buf, size_t len)
+{
+ return __type2str (share, buf, len, sp_share, ARRAY_SIZE(sp_share));
+}
+
+int xfrmnl_sp_str2share(const char *name)
+{
+ return __str2type (name, sp_share, ARRAY_SIZE(sp_share));
+}
+/** @} */
+
+static void xfrm_sp_dump_line(struct nl_object *a, struct nl_dump_params *p)
+{
+ struct xfrmnl_sp* sp = (struct xfrmnl_sp *) a;
+ char dir[32], action[32], share[32], flags[32];
+ char dst[INET6_ADDRSTRLEN+5], src[INET6_ADDRSTRLEN+5];
+ time_t add_time, use_time;
+ struct tm *add_time_tm, *use_time_tm;
+
+ nl_addr2str(xfrmnl_sel_get_saddr (sp->sel), src, sizeof(src));
+ nl_addr2str (xfrmnl_sel_get_daddr (sp->sel), dst, sizeof (dst));
+ nl_af2str (xfrmnl_sel_get_family (sp->sel), dir, 32);
+ nl_dump_line(p, "src %s dst %s family: %s\n", src, dst, dir);
+ nl_dump_line (p, "src port/mask: %d/%d dst port/mask: %d/%d\n",
+ xfrmnl_sel_get_dport (sp->sel), xfrmnl_sel_get_dportmask (sp->sel),
+ xfrmnl_sel_get_sport (sp->sel), xfrmnl_sel_get_sportmask (sp->sel));
+ nl_dump_line (p, "protocol: %s ifindex: %u uid: %u\n",
+ nl_ip_proto2str (xfrmnl_sel_get_proto (sp->sel), dir, sizeof(dir)),
+ xfrmnl_sel_get_ifindex (sp->sel),
+ xfrmnl_sel_get_userid (sp->sel));
+
+ xfrmnl_sp_dir2str (sp->dir, dir, 32);
+ xfrmnl_sp_action2str (sp->action, action, 32);
+ xfrmnl_sp_share2str (sp->share, share, 32);
+ xfrmnl_sp_flags2str (sp->flags, flags, 32);
+ nl_dump_line(p, "\tdir: %s action: %s index: %u priority: %u share: %s flags: %s(0x%x) \n",
+ dir, action, sp->index, sp->priority, share, flags, sp->flags);
+
+ nl_dump_line(p, "\tlifetime configuration: \n");
+ if (sp->lft->soft_byte_limit == XFRM_INF)
+ sprintf (dir, "INF");
+ else
+ sprintf (dir, "%" PRIu64, sp->lft->soft_byte_limit);
+ if (sp->lft->soft_packet_limit == XFRM_INF)
+ sprintf (action, "INF");
+ else
+ sprintf (action, "%" PRIu64, sp->lft->soft_packet_limit);
+ if (sp->lft->hard_byte_limit == XFRM_INF)
+ sprintf (flags, "INF");
+ else
+ sprintf (flags, "%" PRIu64, sp->lft->hard_byte_limit);
+ if (sp->lft->hard_packet_limit == XFRM_INF)
+ sprintf (share, "INF");
+ else
+ sprintf (share, "%" PRIu64, sp->lft->hard_packet_limit);
+ nl_dump_line(p, "\t\tsoft limit: %s (bytes), %s (packets) \n", dir, action);
+ nl_dump_line(p, "\t\thard limit: %s (bytes), %s (packets) \n", flags, share);
+ nl_dump_line(p, "\t\tsoft add_time: %llu (seconds), soft use_time: %llu (seconds) \n",
+ sp->lft->soft_add_expires_seconds, sp->lft->soft_use_expires_seconds);
+ nl_dump_line(p, "\t\thard add_time: %llu (seconds), hard use_time: %llu (seconds) \n",
+ sp->lft->hard_add_expires_seconds, sp->lft->hard_use_expires_seconds);
+
+ nl_dump_line(p, "\tlifetime current: \n");
+ nl_dump_line(p, "\t\t%llu bytes, %llu packets\n", sp->curlft.bytes, sp->curlft.packets);
+
+ if (sp->curlft.add_time != 0)
+ {
+ add_time = sp->curlft.add_time;
+ add_time_tm = gmtime (&add_time);
+ strftime (dst, INET6_ADDRSTRLEN+5, "%Y-%m-%d %H-%M-%S", add_time_tm);
+ }
+ else
+ {
+ sprintf (dst, "%s", "-");
+ }
+
+ if (sp->curlft.use_time != 0)
+ {
+ use_time = sp->curlft.use_time;
+ use_time_tm = gmtime (&use_time);
+ strftime (src, INET6_ADDRSTRLEN+5, "%Y-%m-%d %H-%M-%S", use_time_tm);
+ }
+ else
+ {
+ sprintf (src, "%s", "-");
+ }
+ nl_dump_line(p, "\t\tadd_time: %s, use_time: %s\n", dst, src);
+
+ if (sp->ce_mask & XFRM_SP_ATTR_SECCTX)
+ {
+ nl_dump_line(p, "\tUser security context: \n");
+ nl_dump_line(p, "\t\tlen: %d exttype: %d Algo: %d DOI: %d ctxlen: %d\n",
+ sp->sec_ctx->len, sp->sec_ctx->exttype,
+ sp->sec_ctx->ctx_alg, sp->sec_ctx->ctx_doi, sp->sec_ctx->ctx_len);
+ nl_dump_line (p, "\t\tctx: %s \n", sp->sec_ctx->ctx);
+ }
+
+ xfrmnl_sp_type2str (sp->uptype.type, flags, 32);
+ if (sp->ce_mask & XFRM_SP_ATTR_POLTYPE)
+ nl_dump_line(p, "\tUser policy type: %s\n", flags);
+
+ if (sp->ce_mask & XFRM_SP_ATTR_TMPL)
+ {
+ struct xfrmnl_user_tmpl* utmpl;
+
+ nl_dump_line(p, "\tUser template: \n");
+
+ nl_list_for_each_entry(utmpl, &sp->usertmpl_list, utmpl_list)
+ xfrmnl_user_tmpl_dump (utmpl, p);
+ }
+
+ if (sp->ce_mask & XFRM_SP_ATTR_MARK)
+ nl_dump_line(p, "\tMark mask: 0x%x Mark value: 0x%x\n", sp->mark.m, sp->mark.v);
+
+ nl_dump(p, "\n");
+}
+
+static void xfrm_sp_dump_details(struct nl_object *a, struct nl_dump_params *p)
+{
+ xfrm_sp_dump_line(a, p);
+}
+
+static void xfrm_sp_dump_stats(struct nl_object *a, struct nl_dump_params *p)
+{
+ xfrm_sp_dump_details(a, p);
+
+ return;
+}
+
+/**
+ * @name XFRM SP Object Allocation/Freeage
+ * @{
+ */
+
+struct xfrmnl_sp* xfrmnl_sp_alloc(void)
+{
+ return (struct xfrmnl_sp*) nl_object_alloc(&xfrm_sp_obj_ops);
+}
+
+void xfrmnl_sp_put(struct xfrmnl_sp* sp)
+{
+ nl_object_put((struct nl_object *) sp);
+}
+
+/** @} */
+
+/**
+ * @name SP Cache Managament
+ * @{
+ */
+
+/**
+ * Build a SP cache including all SPs currently configured in the kernel.
+ * @arg sock Netlink socket.
+ * @arg result Pointer to store resulting cache.
+ *
+ * Allocates a new SP cache, initializes it properly and updates it
+ * to include all SPs currently configured in the kernel.
+ *
+ * @return 0 on success or a negative error code.
+ */
+int xfrmnl_sp_alloc_cache(struct nl_sock *sock, struct nl_cache **result)
+{
+ return nl_cache_alloc_and_fill(&xfrmnl_sp_ops, sock, result);
+}
+
+/**
+ * Look up a SP by policy id and direction
+ * @arg cache SP cache
+ * @arg index Policy Id
+ * @arg dir direction
+ * @return sp handle or NULL if no match was found.
+ */
+struct xfrmnl_sp* xfrmnl_sp_get(struct nl_cache* cache, unsigned int index, unsigned int dir)
+{
+ struct xfrmnl_sp *sp;
+
+ //nl_list_for_each_entry(sp, &cache->c_items, ce_list) {
+ for (sp = (struct xfrmnl_sp*)nl_cache_get_first (cache);
+ sp != NULL;
+ sp = (struct xfrmnl_sp*)nl_cache_get_next ((struct nl_object*)sp))
+ {
+ if (sp->index == index && sp->dir == dir)
+ {
+ nl_object_get((struct nl_object *) sp);
+ return sp;
+ }
+ }
+
+ return NULL;
+}
+
+
+/** @} */
+
+
+static struct nla_policy xfrm_sp_policy[XFRMA_MAX+1] = {
+ [XFRMA_POLICY] = { .minlen = sizeof(struct xfrm_userpolicy_info)},
+ [XFRMA_SEC_CTX] = { .minlen = sizeof(struct xfrm_sec_ctx) },
+ [XFRMA_TMPL] = { .minlen = sizeof(struct xfrm_user_tmpl) },
+ [XFRMA_POLICY_TYPE] = { .minlen = sizeof(struct xfrm_userpolicy_type)},
+ [XFRMA_MARK] = { .minlen = sizeof(struct xfrm_mark) },
+};
+
+static int xfrm_sp_request_update(struct nl_cache *c, struct nl_sock *h)
+{
+ struct xfrm_userpolicy_id sp_id;
+
+ memset (&sp_id, 0, sizeof (sp_id));
+ return nl_send_simple (h, XFRM_MSG_GETPOLICY, NLM_F_DUMP,
+ &sp_id, sizeof (sp_id));
+}
+
+int xfrmnl_sp_parse(struct nlmsghdr *n, struct xfrmnl_sp **result)
+{
+ struct xfrmnl_sp *sp;
+ struct nlattr *tb[XFRMA_MAX + 1];
+ struct xfrm_userpolicy_info *sp_info;
+ int len, err;
+ struct nl_addr* addr;
+
+ sp = xfrmnl_sp_alloc();
+ if (!sp) {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+
+ sp->ce_msgtype = n->nlmsg_type;
+ if (n->nlmsg_type == XFRM_MSG_DELPOLICY)
+ {
+ sp_info = (struct xfrm_userpolicy_info*)((char *)nlmsg_data(n) + sizeof (struct xfrm_userpolicy_id) + NLA_HDRLEN);
+ }
+ else
+ {
+ sp_info = nlmsg_data(n);
+ }
+
+ err = nlmsg_parse(n, sizeof(struct xfrm_userpolicy_info), tb, XFRMA_MAX, xfrm_sp_policy);
+ if (err < 0)
+ {
+ printf ("parse error: %d \n", err);
+ goto errout;
+ }
+
+ if (sp_info->sel.family == AF_INET)
+ addr = nl_addr_build (sp_info->sel.family, &sp_info->sel.daddr.a4, sizeof (sp_info->sel.daddr.a4));
+ else
+ addr = nl_addr_build (sp_info->sel.family, &sp_info->sel.daddr.a6, sizeof (sp_info->sel.daddr.a6));
+ nl_addr_set_prefixlen (addr, sp_info->sel.prefixlen_d);
+ xfrmnl_sel_set_daddr (sp->sel, addr);
+ xfrmnl_sel_set_prefixlen_d (sp->sel, sp_info->sel.prefixlen_d);
+
+ if (sp_info->sel.family == AF_INET)
+ addr = nl_addr_build (sp_info->sel.family, &sp_info->sel.saddr.a4, sizeof (sp_info->sel.saddr.a4));
+ else
+ addr = nl_addr_build (sp_info->sel.family, &sp_info->sel.saddr.a6, sizeof (sp_info->sel.saddr.a6));
+ nl_addr_set_prefixlen (addr, sp_info->sel.prefixlen_s);
+ xfrmnl_sel_set_saddr (sp->sel, addr);
+ xfrmnl_sel_set_prefixlen_s (sp->sel, sp_info->sel.prefixlen_s);
+
+ xfrmnl_sel_set_dport (sp->sel, ntohs (sp_info->sel.dport));
+ xfrmnl_sel_set_dportmask (sp->sel, ntohs (sp_info->sel.dport_mask));
+ xfrmnl_sel_set_sport (sp->sel, ntohs (sp_info->sel.sport));
+ xfrmnl_sel_set_sportmask (sp->sel, ntohs (sp_info->sel.sport_mask));
+ xfrmnl_sel_set_family (sp->sel, sp_info->sel.family);
+ xfrmnl_sel_set_proto (sp->sel, sp_info->sel.proto);
+ xfrmnl_sel_set_ifindex (sp->sel, sp_info->sel.ifindex);
+ xfrmnl_sel_set_userid (sp->sel, sp_info->sel.user);
+ sp->ce_mask |= XFRM_SP_ATTR_SEL;
+
+ sp->lft->soft_byte_limit = sp_info->lft.soft_byte_limit;
+ sp->lft->hard_byte_limit = sp_info->lft.hard_byte_limit;
+ sp->lft->soft_packet_limit = sp_info->lft.soft_packet_limit;
+ sp->lft->hard_packet_limit = sp_info->lft.hard_packet_limit;
+ sp->lft->soft_add_expires_seconds = sp_info->lft.soft_add_expires_seconds;
+ sp->lft->hard_add_expires_seconds = sp_info->lft.hard_add_expires_seconds;
+ sp->lft->soft_use_expires_seconds = sp_info->lft.soft_use_expires_seconds;
+ sp->lft->hard_use_expires_seconds = sp_info->lft.hard_use_expires_seconds;
+ sp->ce_mask |= XFRM_SP_ATTR_LTIME_CFG;
+
+ sp->curlft.bytes = sp_info->curlft.bytes;
+ sp->curlft.packets = sp_info->curlft.packets;
+ sp->curlft.add_time = sp_info->curlft.add_time;
+ sp->curlft.use_time = sp_info->curlft.use_time;
+ sp->ce_mask |= XFRM_SP_ATTR_LTIME_CUR;
+
+ sp->priority = sp_info->priority;
+ sp->index = sp_info->index;
+ sp->dir = sp_info->dir;
+ sp->action = sp_info->action;
+ sp->flags = sp_info->flags;
+ sp->share = sp_info->share;
+ sp->ce_mask |= (XFRM_SP_ATTR_PRIO | XFRM_SP_ATTR_INDEX |
+ XFRM_SP_ATTR_DIR | XFRM_SP_ATTR_ACTION |
+ XFRM_SP_ATTR_FLAGS | XFRM_SP_ATTR_SHARE);
+
+ if (tb[XFRMA_SEC_CTX]) {
+ struct xfrm_user_sec_ctx* ctx = nla_data(tb[XFRMA_SEC_CTX]);
+ len = sizeof (struct xfrmnl_user_sec_ctx) + ctx->ctx_len;
+ if ((sp->sec_ctx = calloc (1, len)) == NULL)
+ {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+ memcpy ((void *)sp->sec_ctx, (void *)ctx, len);
+ sp->ce_mask |= XFRM_SP_ATTR_SECCTX;
+ }
+
+ if (tb[XFRMA_POLICY_TYPE]) {
+ struct xfrm_userpolicy_type* up = nla_data(tb[XFRMA_POLICY_TYPE]);
+ memcpy ((void *)&sp->uptype, (void *)up, sizeof (struct xfrm_userpolicy_type));
+ sp->ce_mask |= XFRM_SP_ATTR_POLTYPE;
+ }
+
+ if (tb[XFRMA_TMPL]) {
+ struct xfrm_user_tmpl* tmpl = nla_data(tb[XFRMA_TMPL]);
+ struct xfrmnl_user_tmpl* sputmpl;
+ uint32_t i;
+ uint32_t num_tmpls = nla_len(tb[XFRMA_TMPL]) / sizeof (*tmpl);
+ struct nl_addr* addr;
+
+ for (i = 0; (i < num_tmpls) && (tmpl); i ++, tmpl++)
+ {
+ if ((sputmpl = xfrmnl_user_tmpl_alloc ()) == NULL)
+ {
+ err = -NLE_NOMEM;
+ goto errout;
+ }
+
+ if (tmpl->family == AF_INET)
+ addr = nl_addr_build(tmpl->family, &tmpl->id.daddr.a4, sizeof (tmpl->id.daddr.a4));
+ else
+ addr = nl_addr_build(tmpl->family, &tmpl->id.daddr.a6, sizeof (tmpl->id.daddr.a6));
+ xfrmnl_user_tmpl_set_daddr (sputmpl, addr);
+ xfrmnl_user_tmpl_set_spi (sputmpl, ntohl(tmpl->id.spi));
+ xfrmnl_user_tmpl_set_proto (sputmpl, tmpl->id.proto);
+ xfrmnl_user_tmpl_set_family (sputmpl, tmpl->family);
+
+ if (tmpl->family == AF_INET)
+ addr = nl_addr_build(tmpl->family, &tmpl->saddr.a4, sizeof (tmpl->saddr.a4));
+ else
+ addr = nl_addr_build(tmpl->family, &tmpl->saddr.a6, sizeof (tmpl->saddr.a6));
+ xfrmnl_user_tmpl_set_saddr (sputmpl, addr);
+
+ xfrmnl_user_tmpl_set_reqid (sputmpl, tmpl->reqid);
+ xfrmnl_user_tmpl_set_mode (sputmpl, tmpl->mode);
+ xfrmnl_user_tmpl_set_share (sputmpl, tmpl->share);
+ xfrmnl_user_tmpl_set_optional (sputmpl, tmpl->optional);
+ xfrmnl_user_tmpl_set_aalgos (sputmpl, tmpl->aalgos);
+ xfrmnl_user_tmpl_set_ealgos (sputmpl, tmpl->ealgos);
+ xfrmnl_user_tmpl_set_calgos (sputmpl, tmpl->calgos);
+ xfrmnl_sp_add_usertemplate (sp, sputmpl);
+
+ sp->ce_mask |= XFRM_SP_ATTR_TMPL;
+ }
+ }
+
+ if (tb[XFRMA_MARK]) {
+ struct xfrm_mark* m = nla_data(tb[XFRMA_MARK]);
+ sp->mark.m = m->m;
+ sp->mark.v = m->v;
+ sp->ce_mask |= XFRM_SP_ATTR_MARK;
+ }
+
+ *result = sp;
+ return 0;
+
+errout:
+ xfrmnl_sp_put(sp);
+ return err;
+}
+
+static int xfrm_sp_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
+ struct nlmsghdr *n, struct nl_parser_param *pp)
+{
+ struct xfrmnl_sp* sp;
+ int err;
+
+ if ((err = xfrmnl_sp_parse(n, &sp)) < 0)
+ {
+ printf ("received error: %d \n", err);
+ return err;
+ }
+
+ err = pp->pp_cb((struct nl_object *) sp, pp);
+
+ xfrmnl_sp_put(sp);
+ return err;
+}
+
+/**
+ * @name XFRM SP Get
+ * @{
+ */
+
+int xfrmnl_sp_build_get_request(unsigned int index, unsigned int dir, unsigned int mark_v, unsigned int mark_m, struct nl_msg **result)
+{
+ struct nl_msg *msg;
+ struct xfrm_userpolicy_id spid;
+ struct xfrm_mark mark;
+
+ memset(&spid, 0, sizeof(spid));
+ spid.index = index;
+ spid.dir = dir;
+
+ if (!(msg = nlmsg_alloc_simple(XFRM_MSG_GETPOLICY, 0)))
+ return -NLE_NOMEM;
+
+ if (nlmsg_append(msg, &spid, sizeof(spid), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ if ((mark_m & mark_v) != 0)
+ {
+ memset(&mark, 0, sizeof(struct xfrm_mark));
+ mark.m = mark_m;
+ mark.v = mark_v;
+
+ NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrm_mark), &mark);
+ }
+
+ *result = msg;
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+}
+
+int xfrmnl_sp_get_kernel(struct nl_sock* sock, unsigned int index, unsigned int dir, unsigned int mark_v, unsigned int mark_m, struct xfrmnl_sp** result)
+{
+ struct nl_msg *msg = NULL;
+ struct nl_object *obj;
+ int err;
+
+ if ((err = xfrmnl_sp_build_get_request(index, dir, mark_m, mark_v, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto(sock, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ if ((err = nl_pickup(sock, &xfrm_sp_msg_parser, &obj)) < 0)
+ return err;
+
+ /* We have used xfrm_sp_msg_parser(), object is definitely a xfrm ae */
+ *result = (struct xfrmnl_sp *) obj;
+
+ /* If an object has been returned, we also need to wait for the ACK */
+ if (err == 0 && obj)
+ nl_wait_for_ack(sock);
+
+ return 0;
+}
+
+/** @} */
+
+static int build_xfrm_sp_message(struct xfrmnl_sp *tmpl, int cmd, int flags, struct nl_msg **result)
+{
+ struct nl_msg* msg;
+ struct xfrm_userpolicy_info sp_info;
+ uint32_t len;
+ struct nl_addr* addr;
+
+ if (!(tmpl->ce_mask & XFRM_SP_ATTR_DIR) ||
+ (!(tmpl->ce_mask & XFRM_SP_ATTR_INDEX) &&
+ !(tmpl->ce_mask & XFRM_SP_ATTR_SEL)))
+ return -NLE_MISSING_ATTR;
+
+ memset ((void*)&sp_info, 0, sizeof (sp_info));
+ if (tmpl->ce_mask & XFRM_SP_ATTR_SEL)
+ {
+ addr = xfrmnl_sel_get_daddr (tmpl->sel);
+ memcpy ((void*)&sp_info.sel.daddr, (void*)nl_addr_get_binary_addr (addr), sizeof (uint8_t) * nl_addr_get_len (addr));
+ addr = xfrmnl_sel_get_saddr (tmpl->sel);
+ memcpy ((void*)&sp_info.sel.saddr, (void*)nl_addr_get_binary_addr (addr), sizeof (uint8_t) * nl_addr_get_len (addr));
+ sp_info.sel.dport = htons (xfrmnl_sel_get_dport (tmpl->sel));
+ sp_info.sel.dport_mask = htons (xfrmnl_sel_get_dportmask (tmpl->sel));
+ sp_info.sel.sport = htons (xfrmnl_sel_get_sport (tmpl->sel));
+ sp_info.sel.sport_mask = htons (xfrmnl_sel_get_sportmask (tmpl->sel));
+ sp_info.sel.family = xfrmnl_sel_get_family (tmpl->sel);
+ sp_info.sel.prefixlen_d = xfrmnl_sel_get_prefixlen_d (tmpl->sel);
+ sp_info.sel.prefixlen_s = xfrmnl_sel_get_prefixlen_s (tmpl->sel);
+ sp_info.sel.proto = xfrmnl_sel_get_proto (tmpl->sel);
+ sp_info.sel.ifindex = xfrmnl_sel_get_ifindex (tmpl->sel);
+ sp_info.sel.user = xfrmnl_sel_get_userid (tmpl->sel);
+ }
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_LTIME_CFG)
+ {
+ sp_info.lft.soft_byte_limit = xfrmnl_ltime_cfg_get_soft_bytelimit (tmpl->lft);
+ sp_info.lft.hard_byte_limit = xfrmnl_ltime_cfg_get_hard_bytelimit (tmpl->lft);
+ sp_info.lft.soft_packet_limit = xfrmnl_ltime_cfg_get_soft_packetlimit (tmpl->lft);
+ sp_info.lft.hard_packet_limit = xfrmnl_ltime_cfg_get_hard_packetlimit (tmpl->lft);
+ sp_info.lft.soft_add_expires_seconds = xfrmnl_ltime_cfg_get_soft_addexpires (tmpl->lft);
+ sp_info.lft.hard_add_expires_seconds = xfrmnl_ltime_cfg_get_hard_addexpires (tmpl->lft);
+ sp_info.lft.soft_use_expires_seconds = xfrmnl_ltime_cfg_get_soft_useexpires (tmpl->lft);
+ sp_info.lft.hard_use_expires_seconds = xfrmnl_ltime_cfg_get_hard_useexpires (tmpl->lft);
+ }
+
+ //Skip current lifetime: cur lifetime can be updated only via AE
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_PRIO)
+ sp_info.priority = tmpl->priority;
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_INDEX)
+ sp_info.index = tmpl->index;
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_DIR)
+ sp_info.dir = tmpl->dir;
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_ACTION)
+ sp_info.action = tmpl->action;
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_FLAGS)
+ sp_info.flags = tmpl->flags;
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_SHARE)
+ sp_info.share = tmpl->share;
+
+ msg = nlmsg_alloc_simple(cmd, flags);
+ if (!msg)
+ return -NLE_NOMEM;
+
+ if (nlmsg_append(msg, &sp_info, sizeof(sp_info), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_SECCTX) {
+ len = (sizeof (struct xfrm_user_sec_ctx)) + tmpl->sec_ctx->ctx_len;
+ NLA_PUT (msg, XFRMA_SEC_CTX, len, tmpl->sec_ctx);
+ }
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_POLTYPE) {
+ len = sizeof (struct xfrm_userpolicy_type);
+ NLA_PUT (msg, XFRMA_POLICY_TYPE, len, &tmpl->uptype);
+ }
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_TMPL) {
+ struct nlattr* tmpls;
+ struct xfrmnl_user_tmpl* utmpl;
+ struct nl_addr* addr;
+
+ if (!(tmpls = nla_nest_start(msg, XFRMA_TMPL)))
+ goto nla_put_failure;
+
+ nl_list_for_each_entry(utmpl, &tmpl->usertmpl_list, utmpl_list) {
+ struct xfrm_user_tmpl* tmpl;
+
+ tmpl = nlmsg_reserve(msg, sizeof(*tmpl), NLMSG_ALIGNTO);
+ if (!tmpl)
+ goto nla_put_failure;
+ addr = xfrmnl_user_tmpl_get_daddr (utmpl);
+ memcpy ((void *)&tmpl->id.daddr, nl_addr_get_binary_addr (addr),
+ nl_addr_get_len (addr));
+ tmpl->id.spi = htonl(xfrmnl_user_tmpl_get_spi (utmpl));
+ tmpl->id.proto = xfrmnl_user_tmpl_get_proto (utmpl);
+ tmpl->family = xfrmnl_user_tmpl_get_family (utmpl);
+ addr = xfrmnl_user_tmpl_get_saddr (utmpl);
+ memcpy ((void *)&tmpl->saddr, nl_addr_get_binary_addr (addr),
+ nl_addr_get_len (addr));
+ tmpl->reqid = xfrmnl_user_tmpl_get_reqid (utmpl);
+ tmpl->mode = xfrmnl_user_tmpl_get_mode (utmpl);
+ tmpl->share = xfrmnl_user_tmpl_get_share (utmpl);
+ tmpl->optional = xfrmnl_user_tmpl_get_optional (utmpl);
+ tmpl->aalgos = xfrmnl_user_tmpl_get_aalgos (utmpl);
+ tmpl->ealgos = xfrmnl_user_tmpl_get_ealgos (utmpl);
+ tmpl->calgos = xfrmnl_user_tmpl_get_calgos (utmpl);
+ }
+ nla_nest_end(msg, tmpls);
+ }
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_MARK) {
+ NLA_PUT (msg, XFRMA_MARK, sizeof (struct xfrm_mark), &tmpl->mark);
+ }
+
+ *result = msg;
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+}
+
+/**
+ * @name XFRM SP Add
+ * @{
+ */
+
+int xfrmnl_sp_build_add_request(struct xfrmnl_sp* tmpl, int flags, struct nl_msg **result)
+{
+ return build_xfrm_sp_message (tmpl, XFRM_MSG_NEWPOLICY, flags, result);
+}
+
+int xfrmnl_sp_add(struct nl_sock* sk, struct xfrmnl_sp* tmpl, int flags)
+{
+ int err;
+ struct nl_msg *msg;
+
+ if ((err = xfrmnl_sp_build_add_request(tmpl, flags, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ return nl_wait_for_ack(sk);
+}
+
+/**
+ * @name XFRM SP Update
+ * @{
+ */
+
+int xfrmnl_sp_build_update_request(struct xfrmnl_sp* tmpl, int flags, struct nl_msg **result)
+{
+ return build_xfrm_sp_message (tmpl, XFRM_MSG_UPDPOLICY, flags, result);
+}
+
+int xfrmnl_sp_update(struct nl_sock* sk, struct xfrmnl_sp* tmpl, int flags)
+{
+ int err;
+ struct nl_msg *msg;
+
+ if ((err = xfrmnl_sp_build_update_request(tmpl, flags, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ return nl_wait_for_ack(sk);
+}
+
+/** @} */
+
+/**
+ * \brief Builds a xfrm_sp_delete_message. Uses either index and direction
+ * or security-context (not set is a valid value), selector and
+ * direction for identification.
+ * Returns error if necessary values aren't set.
+ *
+ * \param tmpl The policy template.
+ * \param cmd The command. Should be XFRM_MSG_DELPOLICY.
+ * \param flags Additional flags
+ * \param result Resulting message.
+ *
+ * \return 0 if successful, else error value < 0
+ */
+static int build_xfrm_sp_delete_message(struct xfrmnl_sp *tmpl, int cmd, int flags, struct nl_msg **result)
+{
+ struct nl_msg* msg;
+ struct xfrm_userpolicy_id spid;
+ struct nl_addr* addr;
+ uint32_t len;
+
+ if (!(tmpl->ce_mask & XFRM_SP_ATTR_DIR) ||
+ (!(tmpl->ce_mask & XFRM_SP_ATTR_INDEX) &&
+ !(tmpl->ce_mask & XFRM_SP_ATTR_SEL)))
+ return -NLE_MISSING_ATTR;
+
+ memset(&spid, 0, sizeof(spid));
+ spid.dir = tmpl->dir;
+ if(tmpl->ce_mask & XFRM_SP_ATTR_INDEX)
+ spid.index = tmpl->index;
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_SEL)
+ {
+ addr = xfrmnl_sel_get_daddr (tmpl->sel);
+ memcpy ((void*)&spid.sel.daddr, (void*)nl_addr_get_binary_addr (addr), sizeof (uint8_t) * nl_addr_get_len (addr));
+ addr = xfrmnl_sel_get_saddr (tmpl->sel);
+ memcpy ((void*)&spid.sel.saddr, (void*)nl_addr_get_binary_addr (addr), sizeof (uint8_t) * nl_addr_get_len (addr));
+ spid.sel.dport = htons (xfrmnl_sel_get_dport (tmpl->sel));
+ spid.sel.dport_mask = htons (xfrmnl_sel_get_dportmask (tmpl->sel));
+ spid.sel.sport = htons (xfrmnl_sel_get_sport (tmpl->sel));
+ spid.sel.sport_mask = htons (xfrmnl_sel_get_sportmask (tmpl->sel));
+ spid.sel.family = xfrmnl_sel_get_family (tmpl->sel);
+ spid.sel.prefixlen_d = xfrmnl_sel_get_prefixlen_d (tmpl->sel);
+ spid.sel.prefixlen_s = xfrmnl_sel_get_prefixlen_s (tmpl->sel);
+ spid.sel.proto = xfrmnl_sel_get_proto (tmpl->sel);
+ spid.sel.ifindex = xfrmnl_sel_get_ifindex (tmpl->sel);
+ spid.sel.user = xfrmnl_sel_get_userid (tmpl->sel);
+ }
+
+ msg = nlmsg_alloc_simple(cmd, flags);
+ if (!msg)
+ return -NLE_NOMEM;
+
+ if (nlmsg_append(msg, &spid, sizeof(spid), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_SECCTX) {
+ len = (sizeof (struct xfrm_user_sec_ctx)) + tmpl->sec_ctx->ctx_len;
+ NLA_PUT (msg, XFRMA_SEC_CTX, len, tmpl->sec_ctx);
+ }
+
+ if (tmpl->ce_mask & XFRM_SP_ATTR_MARK) {
+ len = sizeof (struct xfrm_mark);
+ NLA_PUT (msg, XFRMA_MARK, len, &tmpl->mark);
+ }
+
+ *result = msg;
+ return 0;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -NLE_MSGSIZE;
+}
+
+/**
+ * @name XFRM SA Delete
+ * @{
+ */
+
+int xfrmnl_sp_build_delete_request(struct xfrmnl_sp* tmpl, int flags, struct nl_msg **result)
+{
+ return build_xfrm_sp_delete_message (tmpl, XFRM_MSG_DELPOLICY, flags, result);
+}
+
+int xfrmnl_sp_delete(struct nl_sock* sk, struct xfrmnl_sp* tmpl, int flags)
+{
+ int err;
+ struct nl_msg *msg;
+
+ if ((err = xfrmnl_sp_build_delete_request(tmpl, flags, &msg)) < 0)
+ return err;
+
+ err = nl_send_auto_complete(sk, msg);
+ nlmsg_free(msg);
+ if (err < 0)
+ return err;
+
+ return nl_wait_for_ack(sk);
+}
+
+/** @} */
+
+
+/**
+ * @name Attributes
+ * @{
+ */
+
+struct xfrmnl_sel* xfrmnl_sp_get_sel (struct xfrmnl_sp* sp)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_SEL)
+ return sp->sel;
+ else
+ return NULL;
+}
+
+int xfrmnl_sp_set_sel (struct xfrmnl_sp* sp, struct xfrmnl_sel* sel)
+{
+ /* Release any previously held selector object from the SP */
+ if (sp->sel)
+ xfrmnl_sel_put (sp->sel);
+
+ /* Increment ref count on new selector and save it in the SP */
+ xfrmnl_sel_get (sel);
+ sp->sel = sel;
+ sp->ce_mask |= XFRM_SP_ATTR_SEL;
+
+ return 0;
+}
+
+struct xfrmnl_ltime_cfg* xfrmnl_sp_get_lifetime_cfg (struct xfrmnl_sp* sp)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_LTIME_CFG)
+ return sp->lft;
+ else
+ return NULL;
+}
+
+int xfrmnl_sp_set_lifetime_cfg (struct xfrmnl_sp* sp, struct xfrmnl_ltime_cfg* ltime)
+{
+ /* Release any previously held lifetime cfg object from the SP */
+ if (sp->lft)
+ xfrmnl_ltime_cfg_put (sp->lft);
+
+ /* Increment ref count on new lifetime object and save it in the SP */
+ xfrmnl_ltime_cfg_get (ltime);
+ sp->lft = ltime;
+ sp->ce_mask |= XFRM_SP_ATTR_LTIME_CFG;
+
+ return 0;
+}
+
+int xfrmnl_sp_get_curlifetime (struct xfrmnl_sp* sa, unsigned long long int* curr_bytes,
+ unsigned long long int* curr_packets, unsigned long long int* curr_add_time, unsigned long long int* curr_use_time)
+{
+ if (sa == NULL || curr_bytes == NULL || curr_packets == NULL || curr_add_time == NULL || curr_use_time == NULL)
+ return -1;
+
+ *curr_bytes = sa->curlft.bytes;
+ *curr_packets = sa->curlft.packets;
+ *curr_add_time = sa->curlft.add_time;
+ *curr_use_time = sa->curlft.use_time;
+
+ return 0;
+}
+
+int xfrmnl_sp_get_priority (struct xfrmnl_sp* sp)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_PRIO)
+ return sp->priority;
+ else
+ return -1;
+}
+
+int xfrmnl_sp_set_priority (struct xfrmnl_sp* sp, unsigned int prio)
+{
+ sp->priority = prio;
+ sp->ce_mask |= XFRM_SP_ATTR_PRIO;
+
+ return 0;
+}
+
+int xfrmnl_sp_get_index (struct xfrmnl_sp* sp)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_INDEX)
+ return sp->index;
+ else
+ return -1;
+}
+
+int xfrmnl_sp_set_index (struct xfrmnl_sp* sp, unsigned int index)
+{
+ sp->index = index;
+ sp->ce_mask |= XFRM_SP_ATTR_INDEX;
+
+ return 0;
+}
+
+int xfrmnl_sp_get_dir (struct xfrmnl_sp* sp)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_DIR)
+ return sp->dir;
+ else
+ return -1;
+}
+
+int xfrmnl_sp_set_dir (struct xfrmnl_sp* sp, unsigned int dir)
+{
+ sp->dir = dir;
+ sp->ce_mask |= XFRM_SP_ATTR_DIR;
+
+ return 0;
+}
+
+int xfrmnl_sp_get_action (struct xfrmnl_sp* sp)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_ACTION)
+ return sp->action;
+ else
+ return -1;
+}
+
+int xfrmnl_sp_set_action (struct xfrmnl_sp* sp, unsigned int action)
+{
+ sp->action = action;
+ sp->ce_mask |= XFRM_SP_ATTR_ACTION;
+
+ return 0;
+}
+
+int xfrmnl_sp_get_flags (struct xfrmnl_sp* sp)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_FLAGS)
+ return sp->flags;
+ else
+ return -1;
+}
+
+int xfrmnl_sp_set_flags (struct xfrmnl_sp* sp, unsigned int flags)
+{
+ sp->flags = flags;
+ sp->ce_mask |= XFRM_SP_ATTR_FLAGS;
+
+ return 0;
+}
+
+int xfrmnl_sp_get_share (struct xfrmnl_sp* sp)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_SHARE)
+ return sp->share;
+ else
+ return -1;
+}
+
+int xfrmnl_sp_set_share (struct xfrmnl_sp* sp, unsigned int share)
+{
+ sp->share = share;
+ sp->ce_mask |= XFRM_SP_ATTR_SHARE;
+
+ return 0;
+}
+
+/**
+ * Get the security context.
+ *
+ * @arg sp The xfrmnl_sp object.
+ * @arg len An optional output value for the ctx_str length including the xfrmnl_sp header.
+ * @arg exttype An optional output value.
+ * @arg alg An optional output value for the security context algorithm.
+ * @arg doi An optional output value for the security context domain of interpretation.
+ * @arg ctx_len An optional output value for the security context length, including the
+ * terminating null byte ('\0').
+ * @arg ctx_str An optional buffer large enough for the security context string. It must
+ * contain at least @ctx_len bytes. You are advised to create the ctx_str
+ * buffer one element larger and ensure NUL termination yourself.
+ *
+ * Warning: you must ensure that @ctx_str is large enough. If you don't know the length before-hand,
+ * call xfrmnl_sp_get_sec_ctx() without @ctx_str argument to query only the required buffer size.
+ * This modified API is available in all versions of libnl3 that support the capability
+ * @def NL_CAPABILITY_XFRM_SP_SEC_CTX_LEN (@see nl_has_capability for further information).
+ *
+ * @return 0 on success or a negative error code.
+ */
+int xfrmnl_sp_get_sec_ctx (struct xfrmnl_sp* sp, unsigned int* len, unsigned int* exttype, unsigned int* alg, unsigned int* doi, unsigned int* ctx_len, char* ctx_str)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_SECCTX)
+ {
+ if (len)
+ *len = sizeof (struct xfrmnl_user_sec_ctx) + sp->sec_ctx->ctx_len;
+ if (exttype)
+ *exttype = sp->sec_ctx->exttype;
+ if (alg)
+ *alg = sp->sec_ctx->ctx_alg;
+ if (doi)
+ *doi = sp->sec_ctx->ctx_doi;
+ if (ctx_len)
+ *ctx_len = sp->sec_ctx->ctx_len;
+ if (ctx_str)
+ memcpy ((void *)ctx_str, (void *)sp->sec_ctx->ctx, sp->sec_ctx->ctx_len);
+ }
+ else
+ return -1;
+
+ return 0;
+}
+/**
+ * @brief Set security context (ctx_str) for XFRM Polixy.
+ *
+ * @param sp XFRM Policy
+ * @param len !!! depricated unused parameter !!!
+ * @param exttype netlink message attribute - probably XFRMA_SEC_CTX
+ * @param alg security context algorithm
+ * @param doi security context domain interpretation
+ * @param ctx_len Length of the context string.
+ * @param ctx_str The context string.
+ *
+ * @return 0 if sucessfull, else -1
+ */
+int xfrmnl_sp_set_sec_ctx (struct xfrmnl_sp* sp, unsigned int len __attribute__((unused)), unsigned int exttype, unsigned int alg, unsigned int doi, unsigned int ctx_len, char* ctx_str)
+{
+ /* Free up the old context string and allocate new one */
+ if (sp->sec_ctx)
+ free (sp->sec_ctx);
+ if ((sp->sec_ctx = calloc (1, sizeof (struct xfrmnl_user_sec_ctx) + 1 + ctx_len)) == NULL)
+ return -1;
+
+ /* Save the new info */
+ sp->sec_ctx->len = sizeof (struct xfrmnl_user_sec_ctx) + ctx_len;
+ sp->sec_ctx->exttype = exttype;
+ sp->sec_ctx->ctx_alg = alg;
+ sp->sec_ctx->ctx_doi = doi;
+ sp->sec_ctx->ctx_len = ctx_len;
+ memcpy ((void *)sp->sec_ctx->ctx, (void *)ctx_str, ctx_len);
+ sp->sec_ctx->ctx[ctx_len] = '\0';
+
+ sp->ce_mask |= XFRM_SP_ATTR_SECCTX;
+
+ return 0;
+}
+
+int xfrmnl_sp_get_userpolicy_type (struct xfrmnl_sp* sp)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_POLTYPE)
+ return sp->uptype.type;
+ else
+ return -1;
+}
+
+int xfrmnl_sp_set_userpolicy_type (struct xfrmnl_sp* sp, unsigned int type)
+{
+ sp->uptype.type = type;
+ sp->ce_mask |= XFRM_SP_ATTR_POLTYPE;
+
+ return 0;
+}
+
+void xfrmnl_sp_add_usertemplate(struct xfrmnl_sp *sp, struct xfrmnl_user_tmpl *utmpl)
+{
+ nl_list_add_tail(&utmpl->utmpl_list, &sp->usertmpl_list);
+ sp->nr_user_tmpl++;
+ sp->ce_mask |= XFRM_SP_ATTR_TMPL;
+}
+
+void xfrmnl_sp_remove_usertemplate(struct xfrmnl_sp *sp, struct xfrmnl_user_tmpl *utmpl)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_TMPL) {
+ sp->nr_user_tmpl--;
+ nl_list_del(&utmpl->utmpl_list);
+ }
+}
+
+struct nl_list_head *xfrmnl_sp_get_usertemplates(struct xfrmnl_sp *sp)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_TMPL)
+ return &sp->usertmpl_list;
+
+ return NULL;
+}
+
+int xfrmnl_sp_get_nusertemplates(struct xfrmnl_sp *sp)
+{
+ if (sp->ce_mask & XFRM_SP_ATTR_TMPL)
+ return sp->nr_user_tmpl;
+
+ return 0;
+}
+
+void xfrmnl_sp_foreach_usertemplate(struct xfrmnl_sp *r,
+ void (*cb)(struct xfrmnl_user_tmpl *, void *),
+ void *arg)
+{
+ struct xfrmnl_user_tmpl *utmpl;
+
+ if (r->ce_mask & XFRM_SP_ATTR_TMPL) {
+ nl_list_for_each_entry(utmpl, &r->usertmpl_list, utmpl_list) {
+ cb(utmpl, arg);
+ }
+ }
+}
+
+struct xfrmnl_user_tmpl *xfrmnl_sp_usertemplate_n(struct xfrmnl_sp *r, int n)
+{
+ struct xfrmnl_user_tmpl *utmpl;
+ uint32_t i;
+
+ if (r->ce_mask & XFRM_SP_ATTR_TMPL && r->nr_user_tmpl > n) {
+ i = 0;
+ nl_list_for_each_entry(utmpl, &r->usertmpl_list, utmpl_list) {
+ if (i == n) return utmpl;
+ i++;
+ }
+ }
+ return NULL;
+}
+
+int xfrmnl_sp_get_mark (struct xfrmnl_sp* sp, unsigned int* mark_mask, unsigned int* mark_value)
+{
+ if (mark_mask == NULL || mark_value == NULL)
+ return -1;
+
+ if (sp->ce_mask & XFRM_SP_ATTR_MARK)
+ {
+ *mark_mask = sp->mark.m;
+ *mark_value = sp->mark.v;
+
+ return 0;
+ }
+ else
+ return -1;
+}
+
+int xfrmnl_sp_set_mark (struct xfrmnl_sp* sp, unsigned int value, unsigned int mask)
+{
+ sp->mark.v = value;
+ sp->mark.m = mask;
+ sp->ce_mask |= XFRM_SP_ATTR_MARK;
+
+ return 0;
+}
+
+/** @} */
+
+static struct nl_object_ops xfrm_sp_obj_ops = {
+ .oo_name = "xfrm/sp",
+ .oo_size = sizeof(struct xfrmnl_sp),
+ .oo_constructor = xfrm_sp_alloc_data,
+ .oo_free_data = xfrm_sp_free_data,
+ .oo_clone = xfrm_sp_clone,
+ .oo_dump = {
+ [NL_DUMP_LINE] = xfrm_sp_dump_line,
+ [NL_DUMP_DETAILS] = xfrm_sp_dump_details,
+ [NL_DUMP_STATS] = xfrm_sp_dump_stats,
+ },
+ .oo_compare = xfrm_sp_compare,
+ .oo_attrs2str = xfrm_sp_attrs2str,
+ .oo_id_attrs = (XFRM_SP_ATTR_SEL | XFRM_SP_ATTR_INDEX | XFRM_SP_ATTR_DIR),
+};
+
+static struct nl_af_group xfrm_sp_groups[] = {
+ { AF_UNSPEC, XFRMNLGRP_POLICY },
+ { END_OF_GROUP_LIST },
+};
+
+static struct nl_cache_ops xfrmnl_sp_ops = {
+ .co_name = "xfrm/sp",
+ .co_hdrsize = sizeof(struct xfrm_userpolicy_info),
+ .co_msgtypes = {
+ { XFRM_MSG_NEWPOLICY, NL_ACT_NEW, "new" },
+ { XFRM_MSG_DELPOLICY, NL_ACT_DEL, "del" },
+ { XFRM_MSG_GETPOLICY, NL_ACT_GET, "get" },
+ { XFRM_MSG_UPDPOLICY, NL_ACT_NEW, "update" },
+ END_OF_MSGTYPES_LIST,
+ },
+ .co_protocol = NETLINK_XFRM,
+ .co_groups = xfrm_sp_groups,
+ .co_request_update = xfrm_sp_request_update,
+ .co_msg_parser = xfrm_sp_msg_parser,
+ .co_obj_ops = &xfrm_sp_obj_ops,
+};
+
+/**
+ * @name XFRM SA Cache Managament
+ * @{
+ */
+
+static void __attribute__ ((constructor)) xfrm_sp_init(void)
+{
+ nl_cache_mngt_register(&xfrmnl_sp_ops);
+}
+
+static void __attribute__ ((destructor)) xfrm_sp_exit(void)
+{
+ nl_cache_mngt_unregister(&xfrmnl_sp_ops);
+}
+
+/** @} */
diff --git a/lib/xfrm/template.c b/lib/xfrm/template.c
new file mode 100644
index 00000000..0561869a
--- /dev/null
+++ b/lib/xfrm/template.c
@@ -0,0 +1,341 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * Neither the name of Texas Instruments Incorporated nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**
+ * @ingroup xfrmnl
+ * @defgroup XFRM User Template Object
+ *
+ * Abstract data type representing XFRM SA properties
+ *
+ * @{
+ *
+ * Header
+ * ------
+ * ~~~~{.c}
+ * #include <netlink/xfrm/template.h>
+ * ~~~~
+ */
+
+#include <netlink/xfrm/template.h>
+#include <netlink-private/netlink.h>
+
+void xfrmnl_user_tmpl_free(struct xfrmnl_user_tmpl* utmpl)
+{
+ if (!utmpl)
+ return;
+
+ nl_addr_put (utmpl->id.daddr);
+ nl_addr_put (utmpl->saddr);
+ free(utmpl);
+}
+
+/**
+ * @name Creating User Template Object
+ * @{
+ */
+
+/**
+ * Allocate new user template object.
+ * @return Newly allocated user template object or NULL
+ */
+struct xfrmnl_user_tmpl* xfrmnl_user_tmpl_alloc()
+{
+ struct xfrmnl_user_tmpl* utmpl;
+
+ utmpl = calloc(1, sizeof(struct xfrmnl_user_tmpl));
+ if (!utmpl)
+ return NULL;
+
+ nl_init_list_head(&utmpl->utmpl_list);
+
+ return utmpl;
+}
+
+/**
+ * Clone existing user template object.
+ * @arg utmpl Selector object.
+ * @return Newly allocated user template object being a duplicate of the
+ * specified user template object or NULL if a failure occured.
+ */
+struct xfrmnl_user_tmpl* xfrmnl_user_tmpl_clone(struct xfrmnl_user_tmpl* utmpl)
+{
+ struct xfrmnl_user_tmpl* new;
+
+ new = xfrmnl_user_tmpl_alloc();
+ if (!new)
+ return NULL;
+
+ memcpy(new, utmpl, sizeof(struct xfrmnl_user_tmpl));
+ new->id.daddr = nl_addr_clone (utmpl->id.daddr);
+ new->saddr = nl_addr_clone (utmpl->saddr);
+
+ return new;
+}
+
+/** @} */
+
+/**
+ * @name XFRM Template Mode Translations
+ * @{
+ */
+static const struct trans_tbl tmpl_modes[] = {
+ __ADD(XFRM_MODE_TRANSPORT, transport),
+ __ADD(XFRM_MODE_TUNNEL, tunnel),
+ __ADD(XFRM_MODE_ROUTEOPTIMIZATION, route optimization),
+ __ADD(XFRM_MODE_IN_TRIGGER, in trigger),
+ __ADD(XFRM_MODE_BEET, beet),
+};
+
+char* xfrmnl_user_tmpl_mode2str(int mode, char *buf, size_t len)
+{
+ return __type2str (mode, buf, len, tmpl_modes, ARRAY_SIZE(tmpl_modes));
+}
+
+int xfrmnl_user_tmpl_str2mode(const char *name)
+{
+ return __str2type (name, tmpl_modes, ARRAY_SIZE(tmpl_modes));
+}
+/** @} */
+
+/**
+ * @name Miscellaneous
+ * @{
+ */
+
+/**
+ * Compares two user template objects.
+ * @arg a A user template object.
+ * @arg b Another user template object.
+ *
+ * @return Non zero if difference is found, 0 otherwise if both
+ * the objects are identical.
+ */
+int xfrmnl_user_tmpl_cmp(struct xfrmnl_user_tmpl* a, struct xfrmnl_user_tmpl* b)
+{
+ /* Check for any differences */
+ if ((nl_addr_cmp_prefix (a->id.daddr, b->id.daddr) != 0) ||
+ (a->id.spi != b->id.spi) ||
+ (a->id.proto && (a->id.proto != b->id.proto)) ||
+ (nl_addr_cmp_prefix (a->saddr, b->saddr) != 0) ||
+ (a->family != b->family) ||
+ (a->reqid != b->reqid) ||
+ (a->mode != b->mode) ||
+ (a->share != b->share) ||
+ (a->aalgos != b->aalgos) ||
+ (a->ealgos != b->ealgos) ||
+ (a->calgos != b->calgos))
+ return 1;
+
+ /* The objects are identical */
+ return 0;
+}
+
+void xfrmnl_user_tmpl_dump(struct xfrmnl_user_tmpl* tmpl, struct nl_dump_params *p)
+{
+ char dst[INET6_ADDRSTRLEN+5], src[INET6_ADDRSTRLEN+5];
+ char buf [128];
+
+ nl_dump_line(p, "\t\tsrc %s dst %s family: %s \n",
+ nl_addr2str(tmpl->saddr, src, sizeof(src)),
+ nl_addr2str (tmpl->id.daddr, dst, sizeof (dst)),
+ nl_af2str (tmpl->family, buf, 128));
+ nl_dump_line (p, "\t\tprotocol: %s spi: 0x%x reqid: %u mode: %s\n",
+ nl_ip_proto2str (tmpl->id.proto, buf, sizeof(buf)),
+ tmpl->id.spi, tmpl->reqid,
+ xfrmnl_user_tmpl_mode2str (tmpl->mode, buf, 128));
+ nl_dump_line (p, "\t\tAuth Algo: 0x%x Crypto Algo: 0x%x Compr Algo: 0x%x\n",
+ tmpl->aalgos, tmpl->ealgos, tmpl->calgos);
+
+ return;
+}
+
+/** @} */
+
+/**
+ * @name Attributes
+ * @{
+ */
+struct nl_addr* xfrmnl_user_tmpl_get_daddr (struct xfrmnl_user_tmpl* utmpl)
+{
+ return utmpl->id.daddr;
+}
+
+int xfrmnl_user_tmpl_set_daddr (struct xfrmnl_user_tmpl* utmpl, struct nl_addr* addr)
+{
+ /* Increment reference counter on this to keep this address
+ * object around while user template in use */
+ nl_addr_get(addr);
+
+ utmpl->id.daddr = addr;
+
+ return 0;
+}
+
+int xfrmnl_user_tmpl_get_spi (struct xfrmnl_user_tmpl* utmpl)
+{
+ return utmpl->id.spi;
+}
+
+int xfrmnl_user_tmpl_set_spi (struct xfrmnl_user_tmpl* utmpl, unsigned int spi)
+{
+ utmpl->id.spi = spi;
+
+ return 0;
+}
+
+int xfrmnl_user_tmpl_get_proto (struct xfrmnl_user_tmpl* utmpl)
+{
+ return utmpl->id.proto;
+}
+
+int xfrmnl_user_tmpl_set_proto (struct xfrmnl_user_tmpl* utmpl, unsigned int protocol)
+{
+ utmpl->id.proto = protocol;
+
+ return 0;
+}
+
+int xfrmnl_user_tmpl_get_family(struct xfrmnl_user_tmpl *utmpl)
+{
+ return utmpl->family;
+}
+
+int xfrmnl_user_tmpl_set_family(struct xfrmnl_user_tmpl *utmpl, unsigned int family)
+{
+ utmpl->family = family;
+
+ return 0;
+}
+
+struct nl_addr* xfrmnl_user_tmpl_get_saddr (struct xfrmnl_user_tmpl* utmpl)
+{
+ return utmpl->saddr;
+}
+
+int xfrmnl_user_tmpl_set_saddr (struct xfrmnl_user_tmpl* utmpl, struct nl_addr* addr)
+{
+ /* Increment reference counter on this to keep this address
+ * object around while user template in use */
+ nl_addr_get(addr);
+
+ utmpl->saddr = addr;
+
+ return 0;
+}
+
+int xfrmnl_user_tmpl_get_reqid (struct xfrmnl_user_tmpl* utmpl)
+{
+ return utmpl->reqid;
+}
+
+int xfrmnl_user_tmpl_set_reqid (struct xfrmnl_user_tmpl* utmpl, unsigned int reqid)
+{
+ utmpl->reqid = reqid;
+
+ return 0;
+}
+
+int xfrmnl_user_tmpl_get_mode (struct xfrmnl_user_tmpl* utmpl)
+{
+ return utmpl->mode;
+}
+
+int xfrmnl_user_tmpl_set_mode (struct xfrmnl_user_tmpl* utmpl, unsigned int mode)
+{
+ utmpl->mode = mode;
+
+ return 0;
+}
+
+int xfrmnl_user_tmpl_get_share (struct xfrmnl_user_tmpl* utmpl)
+{
+ return utmpl->share;
+}
+
+int xfrmnl_user_tmpl_set_share (struct xfrmnl_user_tmpl* utmpl, unsigned int share)
+{
+ utmpl->share = share;
+
+ return 0;
+}
+
+int xfrmnl_user_tmpl_get_optional (struct xfrmnl_user_tmpl* utmpl)
+{
+ return utmpl->optional;
+}
+
+int xfrmnl_user_tmpl_set_optional (struct xfrmnl_user_tmpl* utmpl, unsigned int optional)
+{
+ utmpl->optional = optional;
+
+ return 0;
+}
+
+int xfrmnl_user_tmpl_get_aalgos (struct xfrmnl_user_tmpl* utmpl)
+{
+ return utmpl->aalgos;
+}
+
+int xfrmnl_user_tmpl_set_aalgos (struct xfrmnl_user_tmpl* utmpl, unsigned int aalgos)
+{
+ utmpl->aalgos = aalgos;
+
+ return 0;
+}
+
+int xfrmnl_user_tmpl_get_ealgos (struct xfrmnl_user_tmpl* utmpl)
+{
+ return utmpl->ealgos;
+}
+
+int xfrmnl_user_tmpl_set_ealgos (struct xfrmnl_user_tmpl* utmpl, unsigned int ealgos)
+{
+ utmpl->ealgos = ealgos;
+
+ return 0;
+}
+
+int xfrmnl_user_tmpl_get_calgos (struct xfrmnl_user_tmpl* utmpl)
+{
+ return utmpl->calgos;
+}
+
+int xfrmnl_user_tmpl_set_calgos (struct xfrmnl_user_tmpl* utmpl, unsigned int calgos)
+{
+ utmpl->calgos = calgos;
+
+ return 0;
+}
+
+/** @} */
diff --git a/libnl-3.sym b/libnl-3.sym
new file mode 100644
index 00000000..82d2f072
--- /dev/null
+++ b/libnl-3.sym
@@ -0,0 +1,365 @@
+libnl_3 {
+global:
+ # these functions are in private header files and should have never
+ # been exported. We might hide them later.
+ nl_cache_parse;
+
+ # these functions are in private header files and should have never
+ # been exported. They are used by libnl internals
+ __flags2str;
+ __list_str2type;
+ __list_type2str;
+ __nl_read_num_str_file;
+ __str2flags;
+ __str2type;
+ __trans_list_add;
+ __trans_list_clear;
+ __type2str;
+
+ # internal symbols that are in public headers
+ __nl_cache_mngt_require;
+
+ # variables
+ nl_debug;
+ nl_debug_dp;
+
+ nl_addr2str;
+ nl_addr_alloc;
+ nl_addr_alloc_attr;
+ nl_addr_build;
+ nl_addr_clone;
+ nl_addr_cmp;
+ nl_addr_cmp_prefix;
+ nl_addr_fill_sockaddr;
+ nl_addr_get;
+ nl_addr_get_binary_addr;
+ nl_addr_get_family;
+ nl_addr_get_len;
+ nl_addr_get_prefixlen;
+ nl_addr_guess_family;
+ nl_addr_info;
+ nl_addr_iszero;
+ nl_addr_parse;
+ nl_addr_put;
+ nl_addr_resolve;
+ nl_addr_set_binary_addr;
+ nl_addr_set_family;
+ nl_addr_set_prefixlen;
+ nl_addr_shared;
+ nl_addr_valid;
+ nl_af2str;
+ nl_auto_complete;
+ nl_cache_add;
+ nl_cache_alloc;
+ nl_cache_alloc_and_fill;
+ nl_cache_alloc_name;
+ nl_cache_clear;
+ nl_cache_clone;
+ nl_cache_dump;
+ nl_cache_dump_filter;
+ nl_cache_find;
+ nl_cache_foreach;
+ nl_cache_foreach_filter;
+ nl_cache_free;
+ nl_cache_get;
+ nl_cache_get_first;
+ nl_cache_get_last;
+ nl_cache_get_next;
+ nl_cache_get_ops;
+ nl_cache_get_prev;
+ nl_cache_include;
+ nl_cache_is_empty;
+ nl_cache_mark_all;
+ nl_cache_mngr_add;
+ nl_cache_mngr_add_cache;
+ nl_cache_mngr_alloc;
+ nl_cache_mngr_data_ready;
+ nl_cache_mngr_free;
+ nl_cache_mngr_get_fd;
+ nl_cache_mngr_info;
+ nl_cache_mngr_poll;
+ nl_cache_mngt_provide;
+ nl_cache_mngt_register;
+ nl_cache_mngt_require;
+ nl_cache_mngt_require_safe;
+ nl_cache_mngt_unprovide;
+ nl_cache_mngt_unregister;
+ nl_cache_move;
+ nl_cache_nitems;
+ nl_cache_nitems_filter;
+ nl_cache_ops_associate;
+ nl_cache_ops_associate_safe;
+ nl_cache_ops_foreach;
+ nl_cache_ops_get;
+ nl_cache_ops_lookup;
+ nl_cache_ops_lookup_safe;
+ nl_cache_ops_put;
+ nl_cache_ops_set_flags;
+ nl_cache_parse_and_add;
+ nl_cache_pickup;
+ nl_cache_put;
+ nl_cache_refill;
+ nl_cache_remove;
+ nl_cache_resync;
+ nl_cache_search;
+ nl_cache_set_arg1;
+ nl_cache_set_arg2;
+ nl_cache_set_flags;
+ nl_cache_subset;
+ nl_cancel_down_bits;
+ nl_cancel_down_bytes;
+ nl_cancel_down_us;
+ nl_cb_active_type;
+ nl_cb_alloc;
+ nl_cb_clone;
+ nl_cb_err;
+ nl_cb_get;
+ nl_cb_overwrite_recv;
+ nl_cb_overwrite_recvmsgs;
+ nl_cb_overwrite_send;
+ nl_cb_put;
+ nl_cb_set;
+ nl_cb_set_all;
+ nl_close;
+ nl_complete_msg;
+ nl_connect;
+ nl_data_alloc;
+ nl_data_alloc_attr;
+ nl_data_append;
+ nl_data_clone;
+ nl_data_cmp;
+ nl_data_free;
+ nl_data_get;
+ nl_data_get_size;
+ nl_dump;
+ nl_dump_line;
+ nl_ether_proto2str;
+ nl_get_psched_hz;
+ nl_get_user_hz;
+ nl_geterror;
+ nl_has_capability;
+ nl_hash;
+ nl_hash_any;
+ nl_hash_table_add;
+ nl_hash_table_alloc;
+ nl_hash_table_del;
+ nl_hash_table_free;
+ nl_hash_table_lookup;
+ nl_ip_proto2str;
+ nl_join_groups;
+ nl_llproto2str;
+ nl_msec2str;
+ nl_msg_dump;
+ nl_msg_parse;
+ nl_msgtype_lookup;
+ nl_new_line;
+ nl_nlfamily2str;
+ nl_nlmsg_flags2str;
+ nl_nlmsgtype2str;
+ nl_object_alloc;
+ nl_object_alloc_name;
+ nl_object_attr_list;
+ nl_object_attrs2str;
+ nl_object_clone;
+ nl_object_diff;
+ nl_object_dump;
+ nl_object_dump_buf;
+ nl_object_free;
+ nl_object_get;
+ nl_object_get_cache;
+ nl_object_get_id_attrs;
+ nl_object_get_msgtype;
+ nl_object_get_ops;
+ nl_object_get_refcnt;
+ nl_object_get_type;
+ nl_object_identical;
+ nl_object_is_marked;
+ nl_object_keygen;
+ nl_object_mark;
+ nl_object_match_filter;
+ nl_object_put;
+ nl_object_shared;
+ nl_object_unmark;
+ nl_object_update;
+ nl_perror;
+ nl_pickup;
+ nl_prob2int;
+ nl_rate2str;
+ nl_recv;
+ nl_recvmsgs;
+ nl_recvmsgs_default;
+ nl_recvmsgs_report;
+ nl_send;
+ nl_send_auto;
+ nl_send_auto_complete;
+ nl_send_iovec;
+ nl_send_simple;
+ nl_send_sync;
+ nl_sendmsg;
+ nl_sendto;
+ nl_size2int;
+ nl_size2str;
+ nl_socket_add_membership;
+ nl_socket_add_memberships;
+ nl_socket_alloc;
+ nl_socket_alloc_cb;
+ nl_socket_disable_auto_ack;
+ nl_socket_disable_msg_peek;
+ nl_socket_disable_seq_check;
+ nl_socket_drop_membership;
+ nl_socket_drop_memberships;
+ nl_socket_enable_auto_ack;
+ nl_socket_enable_msg_peek;
+ nl_socket_free;
+ nl_socket_get_cb;
+ nl_socket_get_fd;
+ nl_socket_get_local_port;
+ nl_socket_get_msg_buf_size;
+ nl_socket_get_peer_groups;
+ nl_socket_get_peer_port;
+ nl_socket_modify_cb;
+ nl_socket_modify_err_cb;
+ nl_socket_recv_pktinfo;
+ nl_socket_set_buffer_size;
+ nl_socket_set_cb;
+ nl_socket_set_local_port;
+ nl_socket_set_msg_buf_size;
+ nl_socket_set_nonblocking;
+ nl_socket_set_passcred;
+ nl_socket_set_peer_groups;
+ nl_socket_set_peer_port;
+ nl_socket_use_seq;
+ nl_str2af;
+ nl_str2ether_proto;
+ nl_str2ip_proto;
+ nl_str2llproto;
+ nl_str2msec;
+ nl_str2nlfamily;
+ nl_str2nlmsgtype;
+ nl_syserr2nlerr;
+ nl_ticks2us;
+ nl_us2ticks;
+ nl_ver_maj;
+ nl_ver_mic;
+ nl_ver_min;
+ nl_ver_num;
+ nl_wait_for_ack;
+ nla_attr_size;
+ nla_data;
+ nla_find;
+ nla_get_flag;
+ nla_get_msecs;
+ nla_get_string;
+ nla_get_u16;
+ nla_get_u32;
+ nla_get_u64;
+ nla_get_u8;
+ nla_is_nested;
+ nla_len;
+ nla_memcmp;
+ nla_memcpy;
+ nla_nest_cancel;
+ nla_nest_end;
+ nla_nest_start;
+ nla_next;
+ nla_ok;
+ nla_padlen;
+ nla_parse;
+ nla_parse_nested;
+ nla_put;
+ nla_put_addr;
+ nla_put_data;
+ nla_put_flag;
+ nla_put_msecs;
+ nla_put_nested;
+ nla_put_string;
+ nla_put_u16;
+ nla_put_u32;
+ nla_put_u64;
+ nla_put_u8;
+ nla_reserve;
+ nla_strcmp;
+ nla_strdup;
+ nla_strlcpy;
+ nla_total_size;
+ nla_type;
+ nla_validate;
+ nlmsg_alloc;
+ nlmsg_alloc_simple;
+ nlmsg_alloc_size;
+ nlmsg_append;
+ nlmsg_attrdata;
+ nlmsg_attrlen;
+ nlmsg_convert;
+ nlmsg_data;
+ nlmsg_datalen;
+ nlmsg_expand;
+ nlmsg_find_attr;
+ nlmsg_free;
+ nlmsg_get;
+ nlmsg_get_creds;
+ nlmsg_get_dst;
+ nlmsg_get_max_size;
+ nlmsg_get_proto;
+ nlmsg_get_src;
+ nlmsg_hdr;
+ nlmsg_inherit;
+ nlmsg_next;
+ nlmsg_ok;
+ nlmsg_padlen;
+ nlmsg_parse;
+ nlmsg_put;
+ nlmsg_reserve;
+ nlmsg_set_creds;
+ nlmsg_set_default_size;
+ nlmsg_set_dst;
+ nlmsg_set_proto;
+ nlmsg_set_src;
+ nlmsg_size;
+ nlmsg_tail;
+ nlmsg_total_size;
+ nlmsg_valid_hdr;
+ nlmsg_validate;
+
+ # The following symbols were added during the development of 3.2.26.
+ # Keep them in libnl_3 to avoid breaking users.
+ nl_cache_pickup_checkdup;
+ nl_pickup_keep_syserr;
+
+local:
+ *;
+};
+
+libnl_3_2_26 {
+global:
+ nl_socket_set_fd;
+} libnl_3;
+
+libnl_3_2_27 {
+global:
+ nla_get_s8;
+ nla_put_s8;
+ nla_get_s16;
+ nla_put_s16;
+ nla_get_s32;
+ nla_put_s32;
+ nla_get_s64;
+ nla_put_s64;
+} libnl_3_2_26;
+
+libnl_3_2_28 {
+global:
+ nl_object_diff64;
+} libnl_3_2_27;
+
+libnl_3_2_29 {
+global:
+ nl_cache_include_v2;
+ nl_cache_mngr_add_cache_v2;
+ nl_strerror_l;
+} libnl_3_2_28;
+
+libnl_3_5 {
+global:
+ nla_nest_end_keep_empty;
+} libnl_3_2_29;
diff --git a/libnl-cli-3.sym b/libnl-cli-3.sym
new file mode 100644
index 00000000..71ff2ebe
--- /dev/null
+++ b/libnl-cli-3.sym
@@ -0,0 +1,117 @@
+libnl_3 {
+global:
+ nl_cli_addr_alloc;
+ nl_cli_addr_parse;
+ nl_cli_addr_parse_broadcast;
+ nl_cli_addr_parse_dev;
+ nl_cli_addr_parse_family;
+ nl_cli_addr_parse_label;
+ nl_cli_addr_parse_local;
+ nl_cli_addr_parse_peer;
+ nl_cli_addr_parse_preferred;
+ nl_cli_addr_parse_scope;
+ nl_cli_addr_parse_valid;
+ nl_cli_alloc_cache;
+ nl_cli_alloc_socket;
+ nl_cli_class_alloc;
+ nl_cli_class_alloc_cache;
+ nl_cli_cls_alloc;
+ nl_cli_cls_alloc_cache;
+ nl_cli_cls_parse_ematch;
+ nl_cli_cls_parse_proto;
+ nl_cli_confirm;
+ nl_cli_connect;
+ nl_cli_ct_alloc;
+ nl_cli_ct_alloc_cache;
+ nl_cli_ct_parse_dst;
+ nl_cli_ct_parse_dst_port;
+ nl_cli_ct_parse_family;
+ nl_cli_ct_parse_id;
+ nl_cli_ct_parse_mark;
+ nl_cli_ct_parse_protocol;
+ nl_cli_ct_parse_src;
+ nl_cli_ct_parse_src_port;
+ nl_cli_ct_parse_status;
+ nl_cli_ct_parse_tcp_state;
+ nl_cli_ct_parse_timeout;
+ nl_cli_ct_parse_use;
+ nl_cli_ct_parse_zone;
+ nl_cli_exp_alloc;
+ nl_cli_exp_alloc_cache;
+ nl_cli_exp_parse_class;
+ nl_cli_exp_parse_dst;
+ nl_cli_exp_parse_dst_port;
+ nl_cli_exp_parse_family;
+ nl_cli_exp_parse_flags;
+ nl_cli_exp_parse_fn;
+ nl_cli_exp_parse_helper_name;
+ nl_cli_exp_parse_icmp_code;
+ nl_cli_exp_parse_icmp_id;
+ nl_cli_exp_parse_icmp_type;
+ nl_cli_exp_parse_id;
+ nl_cli_exp_parse_l4protonum;
+ nl_cli_exp_parse_nat_dir;
+ nl_cli_exp_parse_src;
+ nl_cli_exp_parse_src_port;
+ nl_cli_exp_parse_timeout;
+ nl_cli_exp_parse_zone;
+ nl_cli_fatal;
+ nl_cli_link_alloc;
+ nl_cli_link_alloc_cache;
+ nl_cli_link_alloc_cache_family;
+ nl_cli_link_parse_family;
+ nl_cli_link_parse_ifalias;
+ nl_cli_link_parse_ifindex;
+ nl_cli_link_parse_mtu;
+ nl_cli_link_parse_name;
+ nl_cli_link_parse_txqlen;
+ nl_cli_link_parse_weight;
+ nl_cli_load_module;
+ nl_cli_neigh_alloc;
+ nl_cli_neigh_parse_dev;
+ nl_cli_neigh_parse_dst;
+ nl_cli_neigh_parse_family;
+ nl_cli_neigh_parse_lladdr;
+ nl_cli_neigh_parse_state;
+ nl_cli_parse_dumptype;
+ nl_cli_parse_u32;
+ nl_cli_print_version;
+ nl_cli_qdisc_alloc;
+ nl_cli_route_alloc;
+ nl_cli_route_alloc_cache;
+ nl_cli_route_parse_dst;
+ nl_cli_route_parse_family;
+ nl_cli_route_parse_iif;
+ nl_cli_route_parse_metric;
+ nl_cli_route_parse_nexthop;
+ nl_cli_route_parse_pref_src;
+ nl_cli_route_parse_prio;
+ nl_cli_route_parse_protocol;
+ nl_cli_route_parse_scope;
+ nl_cli_route_parse_src;
+ nl_cli_route_parse_table;
+ nl_cli_route_parse_type;
+ nl_cli_rule_alloc;
+ nl_cli_rule_alloc_cache;
+ nl_cli_rule_parse_family;
+ nl_cli_tc_lookup;
+ nl_cli_tc_parse_dev;
+ nl_cli_tc_parse_handle;
+ nl_cli_tc_parse_kind;
+ nl_cli_tc_parse_linktype;
+ nl_cli_tc_parse_mpu;
+ nl_cli_tc_parse_mtu;
+ nl_cli_tc_parse_overhead;
+ nl_cli_tc_parse_parent;
+ nl_cli_tc_register;
+ nl_cli_tc_unregister;
+local:
+ *;
+};
+
+libnl_3_2_28 {
+global:
+ nl_cli_alloc_cache_flags;
+ nl_cli_link_alloc_cache_flags;
+ nl_cli_link_alloc_cache_family_flags;
+} libnl_3;
diff --git a/libnl-genl-3.sym b/libnl-genl-3.sym
new file mode 100644
index 00000000..0f9616d9
--- /dev/null
+++ b/libnl-genl-3.sym
@@ -0,0 +1,51 @@
+libnl_3 {
+global:
+ # these functions are in private header files and should have never
+ # been exported. We might hide them later.
+ genl_resolve_id;
+
+ genl_connect;
+ genl_ctrl_alloc_cache;
+ genl_ctrl_resolve;
+ genl_ctrl_resolve_grp;
+ genl_ctrl_search;
+ genl_ctrl_search_by_name;
+ genl_family_add_grp;
+ genl_family_add_op;
+ genl_family_alloc;
+ genl_family_get_hdrsize;
+ genl_family_get_id;
+ genl_family_get_maxattr;
+ genl_family_get_name;
+ genl_family_get_version;
+ genl_family_ops;
+ genl_family_put;
+ genl_family_set_hdrsize;
+ genl_family_set_id;
+ genl_family_set_maxattr;
+ genl_family_set_name;
+ genl_family_set_version;
+ genl_handle_msg;
+ genl_mngt_resolve;
+ genl_op2name;
+ genl_ops_resolve;
+ genl_register;
+ genl_register_family;
+ genl_send_simple;
+ genl_unregister;
+ genl_unregister_family;
+ genlmsg_attrdata;
+ genlmsg_attrlen;
+ genlmsg_data;
+ genlmsg_hdr;
+ genlmsg_len;
+ genlmsg_parse;
+ genlmsg_put;
+ genlmsg_user_data;
+ genlmsg_user_datalen;
+ genlmsg_user_hdr;
+ genlmsg_valid_hdr;
+ genlmsg_validate;
+local:
+ *;
+};
diff --git a/libnl-idiag-3.sym b/libnl-idiag-3.sym
new file mode 100644
index 00000000..c56cef5c
--- /dev/null
+++ b/libnl-idiag-3.sym
@@ -0,0 +1,109 @@
+libnl_3 {
+global:
+ # ops structure
+ idiagnl_meminfo_obj_ops;
+ idiagnl_msg_obj_ops;
+ idiagnl_req_obj_ops;
+ idiagnl_vegasinfo_obj_ops;
+
+ idiagnl_attrs2str;
+ idiagnl_connect;
+ idiagnl_exts2str;
+ idiagnl_meminfo_alloc;
+ idiagnl_meminfo_get;
+ idiagnl_meminfo_get_fmem;
+ idiagnl_meminfo_get_rmem;
+ idiagnl_meminfo_get_tmem;
+ idiagnl_meminfo_get_wmem;
+ idiagnl_meminfo_put;
+ idiagnl_meminfo_set_fmem;
+ idiagnl_meminfo_set_rmem;
+ idiagnl_meminfo_set_tmem;
+ idiagnl_meminfo_set_wmem;
+ idiagnl_msg_alloc;
+ idiagnl_msg_alloc_cache;
+ idiagnl_msg_get;
+ idiagnl_msg_get_cong;
+ idiagnl_msg_get_dport;
+ idiagnl_msg_get_dst;
+ idiagnl_msg_get_expires;
+ idiagnl_msg_get_family;
+ idiagnl_msg_get_ifindex;
+ idiagnl_msg_get_inode;
+ idiagnl_msg_get_meminfo;
+ idiagnl_msg_get_retrans;
+ idiagnl_msg_get_rqueue;
+ idiagnl_msg_get_shutdown;
+ idiagnl_msg_get_sport;
+ idiagnl_msg_get_src;
+ idiagnl_msg_get_state;
+ idiagnl_msg_get_tclass;
+ idiagnl_msg_get_tcpinfo;
+ idiagnl_msg_get_timer;
+ idiagnl_msg_get_tos;
+ idiagnl_msg_get_uid;
+ idiagnl_msg_get_vegasinfo;
+ idiagnl_msg_get_wqueue;
+ idiagnl_msg_parse;
+ idiagnl_msg_put;
+ idiagnl_msg_set_cong;
+ idiagnl_msg_set_dport;
+ idiagnl_msg_set_dst;
+ idiagnl_msg_set_expires;
+ idiagnl_msg_set_family;
+ idiagnl_msg_set_ifindex;
+ idiagnl_msg_set_inode;
+ idiagnl_msg_set_meminfo;
+ idiagnl_msg_set_retrans;
+ idiagnl_msg_set_rqueue;
+ idiagnl_msg_set_shutdown;
+ idiagnl_msg_set_sport;
+ idiagnl_msg_set_src;
+ idiagnl_msg_set_state;
+ idiagnl_msg_set_tclass;
+ idiagnl_msg_set_tcpinfo;
+ idiagnl_msg_set_timer;
+ idiagnl_msg_set_tos;
+ idiagnl_msg_set_uid;
+ idiagnl_msg_set_vegasinfo;
+ idiagnl_msg_set_wqueue;
+ idiagnl_req_alloc;
+ idiagnl_req_get;
+ idiagnl_req_get_dbs;
+ idiagnl_req_get_dst;
+ idiagnl_req_get_ext;
+ idiagnl_req_get_family;
+ idiagnl_req_get_ifindex;
+ idiagnl_req_get_src;
+ idiagnl_req_get_states;
+ idiagnl_req_parse;
+ idiagnl_req_put;
+ idiagnl_req_set_dbs;
+ idiagnl_req_set_dst;
+ idiagnl_req_set_ext;
+ idiagnl_req_set_family;
+ idiagnl_req_set_ifindex;
+ idiagnl_req_set_src;
+ idiagnl_req_set_states;
+ idiagnl_send_simple;
+ idiagnl_shutdown2str;
+ idiagnl_state2str;
+ idiagnl_str2state;
+ idiagnl_str2timer;
+ idiagnl_tcpopts2str;
+ idiagnl_tcpstate2str;
+ idiagnl_timer2str;
+ idiagnl_vegasinfo_alloc;
+ idiagnl_vegasinfo_get;
+ idiagnl_vegasinfo_get_enabled;
+ idiagnl_vegasinfo_get_minrtt;
+ idiagnl_vegasinfo_get_rtt;
+ idiagnl_vegasinfo_get_rttcnt;
+ idiagnl_vegasinfo_put;
+ idiagnl_vegasinfo_set_enabled;
+ idiagnl_vegasinfo_set_minrtt;
+ idiagnl_vegasinfo_set_rtt;
+ idiagnl_vegasinfo_set_rttcnt;
+local:
+ *;
+};
diff --git a/libnl-nf-3.sym b/libnl-nf-3.sym
new file mode 100644
index 00000000..504e2dda
--- /dev/null
+++ b/libnl-nf-3.sym
@@ -0,0 +1,316 @@
+libnl_3 {
+global:
+ # ops structure
+ ct_obj_ops;
+ exp_obj_ops;
+ log_msg_obj_ops;
+ log_obj_ops;
+ queue_msg_obj_ops;
+ queue_obj_ops;
+
+ nfnl_connect;
+ nfnl_ct_add;
+ nfnl_ct_alloc;
+ nfnl_ct_alloc_cache;
+ nfnl_ct_build_add_request;
+ nfnl_ct_build_delete_request;
+ nfnl_ct_build_query_request;
+ nfnl_ct_del;
+ nfnl_ct_dump_request;
+ nfnl_ct_get;
+ nfnl_ct_get_bytes;
+ nfnl_ct_get_dst;
+ nfnl_ct_get_dst_port;
+ nfnl_ct_get_family;
+ nfnl_ct_get_icmp_code;
+ nfnl_ct_get_icmp_id;
+ nfnl_ct_get_icmp_type;
+ nfnl_ct_get_id;
+ nfnl_ct_get_mark;
+ nfnl_ct_get_packets;
+ nfnl_ct_get_proto;
+ nfnl_ct_get_src;
+ nfnl_ct_get_src_port;
+ nfnl_ct_get_status;
+ nfnl_ct_get_tcp_state;
+ nfnl_ct_get_timeout;
+ nfnl_ct_get_timestamp;
+ nfnl_ct_get_use;
+ nfnl_ct_get_zone;
+ nfnl_ct_put;
+ nfnl_ct_query;
+ nfnl_ct_set_bytes;
+ nfnl_ct_set_dst;
+ nfnl_ct_set_dst_port;
+ nfnl_ct_set_family;
+ nfnl_ct_set_icmp_code;
+ nfnl_ct_set_icmp_id;
+ nfnl_ct_set_icmp_type;
+ nfnl_ct_set_id;
+ nfnl_ct_set_mark;
+ nfnl_ct_set_packets;
+ nfnl_ct_set_proto;
+ nfnl_ct_set_src;
+ nfnl_ct_set_src_port;
+ nfnl_ct_set_status;
+ nfnl_ct_set_tcp_state;
+ nfnl_ct_set_timeout;
+ nfnl_ct_set_timestamp;
+ nfnl_ct_set_use;
+ nfnl_ct_set_zone;
+ nfnl_ct_status2str;
+ nfnl_ct_str2status;
+ nfnl_ct_str2tcp_state;
+ nfnl_ct_tcp_state2str;
+ nfnl_ct_test_bytes;
+ nfnl_ct_test_dst_port;
+ nfnl_ct_test_icmp_code;
+ nfnl_ct_test_icmp_id;
+ nfnl_ct_test_icmp_type;
+ nfnl_ct_test_id;
+ nfnl_ct_test_mark;
+ nfnl_ct_test_packets;
+ nfnl_ct_test_proto;
+ nfnl_ct_test_src_port;
+ nfnl_ct_test_status;
+ nfnl_ct_test_tcp_state;
+ nfnl_ct_test_timeout;
+ nfnl_ct_test_timestamp;
+ nfnl_ct_test_use;
+ nfnl_ct_test_zone;
+ nfnl_ct_unset_status;
+ nfnl_exp_add;
+ nfnl_exp_alloc;
+ nfnl_exp_alloc_cache;
+ nfnl_exp_build_add_request;
+ nfnl_exp_build_delete_request;
+ nfnl_exp_build_query_request;
+ nfnl_exp_del;
+ nfnl_exp_dump_request;
+ nfnl_exp_flags2str;
+ nfnl_exp_get;
+ nfnl_exp_get_class;
+ nfnl_exp_get_dst;
+ nfnl_exp_get_dst_port;
+ nfnl_exp_get_family;
+ nfnl_exp_get_flags;
+ nfnl_exp_get_fn;
+ nfnl_exp_get_helper_name;
+ nfnl_exp_get_icmp_code;
+ nfnl_exp_get_icmp_id;
+ nfnl_exp_get_icmp_type;
+ nfnl_exp_get_id;
+ nfnl_exp_get_l4protonum;
+ nfnl_exp_get_nat_dir;
+ nfnl_exp_get_src;
+ nfnl_exp_get_src_port;
+ nfnl_exp_get_timeout;
+ nfnl_exp_get_zone;
+ nfnl_exp_put;
+ nfnl_exp_query;
+ nfnl_exp_set_class;
+ nfnl_exp_set_dst;
+ nfnl_exp_set_family;
+ nfnl_exp_set_flags;
+ nfnl_exp_set_fn;
+ nfnl_exp_set_helper_name;
+ nfnl_exp_set_icmp;
+ nfnl_exp_set_id;
+ nfnl_exp_set_l4protonum;
+ nfnl_exp_set_nat_dir;
+ nfnl_exp_set_ports;
+ nfnl_exp_set_src;
+ nfnl_exp_set_timeout;
+ nfnl_exp_set_zone;
+ nfnl_exp_str2flags;
+ nfnl_exp_test_class;
+ nfnl_exp_test_dst;
+ nfnl_exp_test_flags;
+ nfnl_exp_test_fn;
+ nfnl_exp_test_helper_name;
+ nfnl_exp_test_icmp;
+ nfnl_exp_test_id;
+ nfnl_exp_test_l4protonum;
+ nfnl_exp_test_nat_dir;
+ nfnl_exp_test_ports;
+ nfnl_exp_test_src;
+ nfnl_exp_test_timeout;
+ nfnl_exp_test_zone;
+ nfnl_exp_unset_flags;
+ nfnl_inet_hook2str;
+ nfnl_log_alloc;
+ nfnl_log_build_change_request;
+ nfnl_log_build_create_request;
+ nfnl_log_build_delete_request;
+ nfnl_log_build_pf_bind;
+ nfnl_log_build_pf_unbind;
+ nfnl_log_change;
+ nfnl_log_copy_mode2str;
+ nfnl_log_create;
+ nfnl_log_delete;
+ nfnl_log_flags2str;
+ nfnl_log_get;
+ nfnl_log_get_alloc_size;
+ nfnl_log_get_copy_mode;
+ nfnl_log_get_copy_range;
+ nfnl_log_get_flush_timeout;
+ nfnl_log_get_group;
+ nfnl_log_get_queue_threshold;
+ nfnl_log_msg_alloc;
+ nfnl_log_msg_get;
+ nfnl_log_msg_get_family;
+ nfnl_log_msg_get_gid;
+ nfnl_log_msg_get_hook;
+ nfnl_log_msg_get_hwaddr;
+ nfnl_log_msg_get_hwproto;
+ nfnl_log_msg_get_indev;
+ nfnl_log_msg_get_mark;
+ nfnl_log_msg_get_outdev;
+ nfnl_log_msg_get_payload;
+ nfnl_log_msg_get_physindev;
+ nfnl_log_msg_get_physoutdev;
+ nfnl_log_msg_get_prefix;
+ nfnl_log_msg_get_seq;
+ nfnl_log_msg_get_seq_global;
+ nfnl_log_msg_get_timestamp;
+ nfnl_log_msg_get_uid;
+ nfnl_log_msg_put;
+ nfnl_log_msg_set_family;
+ nfnl_log_msg_set_gid;
+ nfnl_log_msg_set_hook;
+ nfnl_log_msg_set_hwaddr;
+ nfnl_log_msg_set_hwproto;
+ nfnl_log_msg_set_indev;
+ nfnl_log_msg_set_mark;
+ nfnl_log_msg_set_outdev;
+ nfnl_log_msg_set_payload;
+ nfnl_log_msg_set_physindev;
+ nfnl_log_msg_set_physoutdev;
+ nfnl_log_msg_set_prefix;
+ nfnl_log_msg_set_seq;
+ nfnl_log_msg_set_seq_global;
+ nfnl_log_msg_set_timestamp;
+ nfnl_log_msg_set_uid;
+ nfnl_log_msg_test_gid;
+ nfnl_log_msg_test_hook;
+ nfnl_log_msg_test_hwproto;
+ nfnl_log_msg_test_mark;
+ nfnl_log_msg_test_seq;
+ nfnl_log_msg_test_seq_global;
+ nfnl_log_msg_test_uid;
+ nfnl_log_pf_bind;
+ nfnl_log_pf_unbind;
+ nfnl_log_put;
+ nfnl_log_set_alloc_size;
+ nfnl_log_set_copy_mode;
+ nfnl_log_set_copy_range;
+ nfnl_log_set_flags;
+ nfnl_log_set_flush_timeout;
+ nfnl_log_set_group;
+ nfnl_log_set_queue_threshold;
+ nfnl_log_str2copy_mode;
+ nfnl_log_str2flags;
+ nfnl_log_test_alloc_size;
+ nfnl_log_test_copy_mode;
+ nfnl_log_test_copy_range;
+ nfnl_log_test_flush_timeout;
+ nfnl_log_test_group;
+ nfnl_log_test_queue_threshold;
+ nfnl_log_unset_flags;
+ nfnl_queue_alloc;
+ nfnl_queue_build_change_request;
+ nfnl_queue_build_create_request;
+ nfnl_queue_build_delete_request;
+ nfnl_queue_build_pf_bind;
+ nfnl_queue_build_pf_unbind;
+ nfnl_queue_change;
+ nfnl_queue_copy_mode2str;
+ nfnl_queue_create;
+ nfnl_queue_delete;
+ nfnl_queue_get;
+ nfnl_queue_get_copy_mode;
+ nfnl_queue_get_copy_range;
+ nfnl_queue_get_group;
+ nfnl_queue_get_maxlen;
+ nfnl_queue_msg_alloc;
+ nfnl_queue_msg_build_verdict;
+ nfnl_queue_msg_build_verdict_batch;
+ nfnl_queue_msg_get;
+ nfnl_queue_msg_get_family;
+ nfnl_queue_msg_get_group;
+ nfnl_queue_msg_get_hook;
+ nfnl_queue_msg_get_hwaddr;
+ nfnl_queue_msg_get_hwproto;
+ nfnl_queue_msg_get_indev;
+ nfnl_queue_msg_get_mark;
+ nfnl_queue_msg_get_outdev;
+ nfnl_queue_msg_get_packetid;
+ nfnl_queue_msg_get_payload;
+ nfnl_queue_msg_get_physindev;
+ nfnl_queue_msg_get_physoutdev;
+ nfnl_queue_msg_get_timestamp;
+ nfnl_queue_msg_get_verdict;
+ nfnl_queue_msg_put;
+ nfnl_queue_msg_send_verdict;
+ nfnl_queue_msg_send_verdict_batch;
+ nfnl_queue_msg_send_verdict_payload;
+ nfnl_queue_msg_set_family;
+ nfnl_queue_msg_set_group;
+ nfnl_queue_msg_set_hook;
+ nfnl_queue_msg_set_hwaddr;
+ nfnl_queue_msg_set_hwproto;
+ nfnl_queue_msg_set_indev;
+ nfnl_queue_msg_set_mark;
+ nfnl_queue_msg_set_outdev;
+ nfnl_queue_msg_set_packetid;
+ nfnl_queue_msg_set_payload;
+ nfnl_queue_msg_set_physindev;
+ nfnl_queue_msg_set_physoutdev;
+ nfnl_queue_msg_set_timestamp;
+ nfnl_queue_msg_set_verdict;
+ nfnl_queue_msg_test_family;
+ nfnl_queue_msg_test_group;
+ nfnl_queue_msg_test_hook;
+ nfnl_queue_msg_test_hwaddr;
+ nfnl_queue_msg_test_hwproto;
+ nfnl_queue_msg_test_indev;
+ nfnl_queue_msg_test_mark;
+ nfnl_queue_msg_test_outdev;
+ nfnl_queue_msg_test_packetid;
+ nfnl_queue_msg_test_payload;
+ nfnl_queue_msg_test_physindev;
+ nfnl_queue_msg_test_physoutdev;
+ nfnl_queue_msg_test_timestamp;
+ nfnl_queue_msg_test_verdict;
+ nfnl_queue_pf_bind;
+ nfnl_queue_pf_unbind;
+ nfnl_queue_put;
+ nfnl_queue_set_copy_mode;
+ nfnl_queue_set_copy_range;
+ nfnl_queue_set_group;
+ nfnl_queue_set_maxlen;
+ nfnl_queue_socket_alloc;
+ nfnl_queue_str2copy_mode;
+ nfnl_queue_test_copy_mode;
+ nfnl_queue_test_copy_range;
+ nfnl_queue_test_group;
+ nfnl_queue_test_maxlen;
+ nfnl_send_simple;
+ nfnl_str2inet_hook;
+ nfnl_str2verdict;
+ nfnl_verdict2str;
+ nfnlmsg_alloc_simple;
+ nfnlmsg_ct_group;
+ nfnlmsg_ct_parse;
+ nfnlmsg_exp_group;
+ nfnlmsg_exp_parse;
+ nfnlmsg_family;
+ nfnlmsg_log_msg_parse;
+ nfnlmsg_put;
+ nfnlmsg_queue_msg_parse;
+ nfnlmsg_res_id;
+ nfnlmsg_subsys;
+ nfnlmsg_subtype;
+local:
+ *;
+};
diff --git a/libnl-route-3.sym b/libnl-route-3.sym
new file mode 100644
index 00000000..4a65503f
--- /dev/null
+++ b/libnl-route-3.sym
@@ -0,0 +1,1152 @@
+libnl_3 {
+global:
+ # these functions are in private header files and should have never
+ # been exported. We might hide them later.
+ rtnl_link_af_alloc;
+ rtnl_link_af_data;
+ rtnl_link_af_data_compare;
+ rtnl_link_af_ops_lookup;
+ rtnl_link_af_ops_put;
+ rtnl_link_af_register;
+ rtnl_link_af_unregister;
+ rtnl_link_info_ops_lookup;
+ rtnl_link_info_ops_put;
+ rtnl_link_register_info;
+ rtnl_link_unregister_info;
+ rtnl_tc_build_rate_table;
+ rtnl_tc_clone;
+ rtnl_tc_compare;
+ rtnl_tc_data;
+ rtnl_tc_data_check;
+ rtnl_tc_dump_details;
+ rtnl_tc_dump_line;
+ rtnl_tc_dump_stats;
+ rtnl_tc_free_data;
+ rtnl_tc_msg_build;
+ rtnl_tc_msg_parse;
+ rtnl_tc_register;
+ rtnl_tc_type_register;
+ rtnl_tc_type_unregister;
+ rtnl_tc_unregister;
+
+ # these functions are in private header files and should have never
+ # been exported. They are used by libnl internals
+ rtnl_tc_get_ops;
+ rtnl_tc_lookup_ops;
+
+ # internal symbols that are in public headers
+ rtln_link_policy;
+
+ # ops structure
+ route_obj_ops;
+
+ flnl_lookup;
+ flnl_lookup_build_request;
+ flnl_request_alloc;
+ flnl_request_get_addr;
+ flnl_request_get_fwmark;
+ flnl_request_get_scope;
+ flnl_request_get_table;
+ flnl_request_get_tos;
+ flnl_request_set_addr;
+ flnl_request_set_fwmark;
+ flnl_request_set_scope;
+ flnl_request_set_table;
+ flnl_request_set_tos;
+ flnl_result_alloc;
+ flnl_result_alloc_cache;
+ flnl_result_get_error;
+ flnl_result_get_nexthop_sel;
+ flnl_result_get_prefixlen;
+ flnl_result_get_scope;
+ flnl_result_get_table_id;
+ flnl_result_get_type;
+ flnl_result_put;
+ nl_ovl_strategy2str;
+ nl_police2str;
+ nl_rtgen_request;
+ nl_rtntype2str;
+ nl_str2ovl_strategy;
+ nl_str2police;
+ nl_str2rtntype;
+ rtnl_act_add;
+ rtnl_act_alloc;
+ rtnl_act_append;
+ rtnl_act_build_add_request;
+ rtnl_act_build_change_request;
+ rtnl_act_build_delete_request;
+ rtnl_act_change;
+ rtnl_act_delete;
+ rtnl_act_fill;
+ rtnl_act_get;
+ rtnl_act_parse;
+ rtnl_act_put;
+ rtnl_act_put_all;
+ rtnl_act_remove;
+ rtnl_addr_add;
+ rtnl_addr_alloc;
+ rtnl_addr_alloc_cache;
+ rtnl_addr_build_add_request;
+ rtnl_addr_build_delete_request;
+ rtnl_addr_delete;
+ rtnl_addr_flags2str;
+ rtnl_addr_get;
+ rtnl_addr_get_anycast;
+ rtnl_addr_get_broadcast;
+ rtnl_addr_get_create_time;
+ rtnl_addr_get_family;
+ rtnl_addr_get_flags;
+ rtnl_addr_get_ifindex;
+ rtnl_addr_get_label;
+ rtnl_addr_get_last_update_time;
+ rtnl_addr_get_link;
+ rtnl_addr_get_local;
+ rtnl_addr_get_multicast;
+ rtnl_addr_get_peer;
+ rtnl_addr_get_preferred_lifetime;
+ rtnl_addr_get_prefixlen;
+ rtnl_addr_get_scope;
+ rtnl_addr_get_valid_lifetime;
+ rtnl_addr_put;
+ rtnl_addr_set_anycast;
+ rtnl_addr_set_broadcast;
+ rtnl_addr_set_family;
+ rtnl_addr_set_flags;
+ rtnl_addr_set_ifindex;
+ rtnl_addr_set_label;
+ rtnl_addr_set_link;
+ rtnl_addr_set_local;
+ rtnl_addr_set_multicast;
+ rtnl_addr_set_peer;
+ rtnl_addr_set_preferred_lifetime;
+ rtnl_addr_set_prefixlen;
+ rtnl_addr_set_scope;
+ rtnl_addr_set_valid_lifetime;
+ rtnl_addr_str2flags;
+ rtnl_addr_unset_flags;
+ rtnl_basic_add_action;
+ rtnl_basic_del_action;
+ rtnl_basic_get_ematch;
+ rtnl_basic_get_target;
+ rtnl_basic_set_ematch;
+ rtnl_basic_set_target;
+ rtnl_cgroup_get_ematch;
+ rtnl_cgroup_set_ematch;
+ rtnl_class_add;
+ rtnl_class_alloc;
+ rtnl_class_alloc_cache;
+ rtnl_class_build_add_request;
+ rtnl_class_build_delete_request;
+ rtnl_class_delete;
+ rtnl_class_dsmark_get_bitmask;
+ rtnl_class_dsmark_get_value;
+ rtnl_class_dsmark_set_bitmask;
+ rtnl_class_dsmark_set_value;
+ rtnl_class_foreach_child;
+ rtnl_class_foreach_cls;
+ rtnl_class_get;
+ rtnl_class_leaf_qdisc;
+ rtnl_class_put;
+ rtnl_classid_generate;
+ rtnl_cls_add;
+ rtnl_cls_alloc;
+ rtnl_cls_alloc_cache;
+ rtnl_cls_build_add_request;
+ rtnl_cls_build_change_request;
+ rtnl_cls_build_delete_request;
+ rtnl_cls_change;
+ rtnl_cls_delete;
+ rtnl_cls_get_prio;
+ rtnl_cls_get_protocol;
+ rtnl_cls_put;
+ rtnl_cls_set_prio;
+ rtnl_cls_set_protocol;
+ rtnl_ematch_add_child;
+ rtnl_ematch_alloc;
+ rtnl_ematch_cmp_get;
+ rtnl_ematch_cmp_set;
+ rtnl_ematch_data;
+ rtnl_ematch_fill_attr;
+ rtnl_ematch_free;
+ rtnl_ematch_get_flags;
+ rtnl_ematch_lookup_ops;
+ rtnl_ematch_lookup_ops_by_name;
+ rtnl_ematch_meta_set_lvalue;
+ rtnl_ematch_meta_set_operand;
+ rtnl_ematch_meta_set_rvalue;
+ rtnl_ematch_nbyte_get_layer;
+ rtnl_ematch_nbyte_get_len;
+ rtnl_ematch_nbyte_get_offset;
+ rtnl_ematch_nbyte_get_pattern;
+ rtnl_ematch_nbyte_set_offset;
+ rtnl_ematch_nbyte_set_pattern;
+ rtnl_ematch_offset2txt;
+ rtnl_ematch_opnd2txt;
+ rtnl_ematch_parse_attr;
+ rtnl_ematch_parse_expr;
+ rtnl_ematch_register;
+ rtnl_ematch_set_flags;
+ rtnl_ematch_set_kind;
+ rtnl_ematch_set_name;
+ rtnl_ematch_set_ops;
+ rtnl_ematch_text_get_algo;
+ rtnl_ematch_text_get_from_layer;
+ rtnl_ematch_text_get_from_offset;
+ rtnl_ematch_text_get_len;
+ rtnl_ematch_text_get_pattern;
+ rtnl_ematch_text_get_to_layer;
+ rtnl_ematch_text_get_to_offset;
+ rtnl_ematch_text_set_algo;
+ rtnl_ematch_text_set_from;
+ rtnl_ematch_text_set_pattern;
+ rtnl_ematch_text_set_to;
+ rtnl_ematch_tree_add;
+ rtnl_ematch_tree_alloc;
+ rtnl_ematch_tree_dump;
+ rtnl_ematch_tree_free;
+ rtnl_ematch_unlink;
+ rtnl_ematch_unset_flags;
+ rtnl_fw_set_classid;
+ rtnl_fw_set_mask;
+ rtnl_htb_get_cbuffer;
+ rtnl_htb_get_ceil;
+ rtnl_htb_get_defcls;
+ rtnl_htb_get_level;
+ rtnl_htb_get_prio;
+ rtnl_htb_get_quantum;
+ rtnl_htb_get_rate2quantum;
+ rtnl_htb_get_rate;
+ rtnl_htb_get_rbuffer;
+ rtnl_htb_set_cbuffer;
+ rtnl_htb_set_ceil;
+ rtnl_htb_set_defcls;
+ rtnl_htb_set_level;
+ rtnl_htb_set_prio;
+ rtnl_htb_set_quantum;
+ rtnl_htb_set_rate2quantum;
+ rtnl_htb_set_rate;
+ rtnl_htb_set_rbuffer;
+ rtnl_link_add;
+ rtnl_link_alloc;
+ rtnl_link_alloc_cache;
+ rtnl_link_bond_add;
+ rtnl_link_bond_alloc;
+ rtnl_link_bond_enslave;
+ rtnl_link_bond_enslave_ifindex;
+ rtnl_link_bond_release;
+ rtnl_link_bond_release_ifindex;
+ rtnl_link_bridge_add;
+ rtnl_link_bridge_alloc;
+ rtnl_link_bridge_flags2str;
+ rtnl_link_bridge_get_cost;
+ rtnl_link_bridge_get_flags;
+ rtnl_link_bridge_get_port_state;
+ rtnl_link_bridge_get_priority;
+ rtnl_link_bridge_has_ext_info;
+ rtnl_link_bridge_set_cost;
+ rtnl_link_bridge_set_flags;
+ rtnl_link_bridge_set_port_state;
+ rtnl_link_bridge_set_priority;
+ rtnl_link_bridge_str2flags;
+ rtnl_link_bridge_unset_flags;
+ rtnl_link_build_add_request;
+ rtnl_link_build_change_request;
+ rtnl_link_build_delete_request;
+ rtnl_link_build_get_request;
+ rtnl_link_can_berr;
+ rtnl_link_can_berr_rx;
+ rtnl_link_can_berr_tx;
+ rtnl_link_can_ctrlmode2str;
+ rtnl_link_can_freq;
+ rtnl_link_can_get_bitrate;
+ rtnl_link_can_get_bittiming;
+ rtnl_link_can_get_bt_const;
+ rtnl_link_can_get_ctrlmode;
+ rtnl_link_can_get_restart_ms;
+ rtnl_link_can_get_sample_point;
+ rtnl_link_can_restart;
+ rtnl_link_can_set_bitrate;
+ rtnl_link_can_set_bittiming;
+ rtnl_link_can_set_ctrlmode;
+ rtnl_link_can_set_restart_ms;
+ rtnl_link_can_set_sample_point;
+ rtnl_link_can_state;
+ rtnl_link_can_str2ctrlmode;
+ rtnl_link_can_unset_ctrlmode;
+ rtnl_link_carrier2str;
+ rtnl_link_change;
+ rtnl_link_delete;
+ rtnl_link_enslave;
+ rtnl_link_enslave_ifindex;
+ rtnl_link_fill_info;
+ rtnl_link_flags2str;
+ rtnl_link_get;
+ rtnl_link_get_addr;
+ rtnl_link_get_arptype;
+ rtnl_link_get_broadcast;
+ rtnl_link_get_by_name;
+ rtnl_link_get_carrier;
+ rtnl_link_get_family;
+ rtnl_link_get_flags;
+ rtnl_link_get_group;
+ rtnl_link_get_ifalias;
+ rtnl_link_get_ifindex;
+ rtnl_link_get_info_type;
+ rtnl_link_get_kernel;
+ rtnl_link_get_link;
+ rtnl_link_get_linkmode;
+ rtnl_link_get_master;
+ rtnl_link_get_mtu;
+ rtnl_link_get_name;
+ rtnl_link_get_ns_fd;
+ rtnl_link_get_ns_pid;
+ rtnl_link_get_num_rx_queues;
+ rtnl_link_get_num_tx_queues;
+ rtnl_link_get_num_vf;
+ rtnl_link_get_operstate;
+ rtnl_link_get_phys_port_id;
+ rtnl_link_get_pmtudisc;
+ rtnl_link_get_promiscuity;
+ rtnl_link_get_qdisc;
+ rtnl_link_get_stat;
+ rtnl_link_get_txqlen;
+ rtnl_link_get_type;
+ rtnl_link_get_weight;
+ rtnl_link_i2name;
+ rtnl_link_inet_devconf2str;
+ rtnl_link_inet_get_conf;
+ rtnl_link_inet_set_conf;
+ rtnl_link_inet_str2devconf;
+ rtnl_link_info_parse;
+ rtnl_link_ip6_tnl_add;
+ rtnl_link_ip6_tnl_alloc;
+ rtnl_link_ip6_tnl_get_encaplimit;
+ rtnl_link_ip6_tnl_get_flags;
+ rtnl_link_ip6_tnl_get_flowinfo;
+ rtnl_link_ip6_tnl_get_link;
+ rtnl_link_ip6_tnl_get_local;
+ rtnl_link_ip6_tnl_get_proto;
+ rtnl_link_ip6_tnl_get_remote;
+ rtnl_link_ip6_tnl_get_tos;
+ rtnl_link_ip6_tnl_get_ttl;
+ rtnl_link_ip6_tnl_set_encaplimit;
+ rtnl_link_ip6_tnl_set_flags;
+ rtnl_link_ip6_tnl_set_flowinfo;
+ rtnl_link_ip6_tnl_set_link;
+ rtnl_link_ip6_tnl_set_local;
+ rtnl_link_ip6_tnl_set_proto;
+ rtnl_link_ip6_tnl_set_remote;
+ rtnl_link_ip6_tnl_set_tos;
+ rtnl_link_ip6_tnl_set_ttl;
+ rtnl_link_ipgre_add;
+ rtnl_link_ipgre_alloc;
+ rtnl_link_ipgre_get_iflags;
+ rtnl_link_ipgre_get_ikey;
+ rtnl_link_ipgre_get_link;
+ rtnl_link_ipgre_get_local;
+ rtnl_link_ipgre_get_oflags;
+ rtnl_link_ipgre_get_okey;
+ rtnl_link_ipgre_get_remote;
+ rtnl_link_ipgre_get_tos;
+ rtnl_link_ipgre_get_ttl;
+ rtnl_link_ipgre_set_iflags;
+ rtnl_link_ipgre_set_ikey;
+ rtnl_link_ipgre_set_link;
+ rtnl_link_ipgre_set_local;
+ rtnl_link_ipgre_set_oflags;
+ rtnl_link_ipgre_set_okey;
+ rtnl_link_ipgre_set_pmtudisc;
+ rtnl_link_ipgre_set_remote;
+ rtnl_link_ipgre_set_tos;
+ rtnl_link_ipgre_set_ttl;
+ rtnl_link_ipip_add;
+ rtnl_link_ipip_alloc;
+ rtnl_link_ipip_get_link;
+ rtnl_link_ipip_get_local;
+ rtnl_link_ipip_get_pmtudisc;
+ rtnl_link_ipip_get_remote;
+ rtnl_link_ipip_get_tos;
+ rtnl_link_ipip_get_ttl;
+ rtnl_link_ipip_set_link;
+ rtnl_link_ipip_set_local;
+ rtnl_link_ipip_set_pmtudisc;
+ rtnl_link_ipip_set_remote;
+ rtnl_link_ipip_set_tos;
+ rtnl_link_ipip_set_ttl;
+ rtnl_link_ipvti_add;
+ rtnl_link_ipvti_alloc;
+ rtnl_link_ipvti_get_ikey;
+ rtnl_link_ipvti_get_link;
+ rtnl_link_ipvti_get_local;
+ rtnl_link_ipvti_get_okey;
+ rtnl_link_ipvti_get_remote;
+ rtnl_link_ipvti_set_ikey;
+ rtnl_link_ipvti_set_link;
+ rtnl_link_ipvti_set_local;
+ rtnl_link_ipvti_set_okey;
+ rtnl_link_ipvti_set_remote;
+ rtnl_link_is_bridge;
+ rtnl_link_is_can;
+ rtnl_link_is_ip6_tnl;
+ rtnl_link_is_ipgre;
+ rtnl_link_is_ipip;
+ rtnl_link_is_ipvti;
+ rtnl_link_is_macvlan;
+ rtnl_link_is_sit;
+ rtnl_link_is_veth;
+ rtnl_link_is_vlan;
+ rtnl_link_is_vxlan;
+ rtnl_link_macvlan_alloc;
+ rtnl_link_macvlan_flags2str;
+ rtnl_link_macvlan_get_flags;
+ rtnl_link_macvlan_get_mode;
+ rtnl_link_macvlan_mode2str;
+ rtnl_link_macvlan_set_flags;
+ rtnl_link_macvlan_set_mode;
+ rtnl_link_macvlan_str2flags;
+ rtnl_link_macvlan_str2mode;
+ rtnl_link_macvlan_unset_flags;
+ rtnl_link_mode2str;
+ rtnl_link_name2i;
+ rtnl_link_operstate2str;
+ rtnl_link_put;
+ rtnl_link_release;
+ rtnl_link_release_ifindex;
+ rtnl_link_set_addr;
+ rtnl_link_set_arptype;
+ rtnl_link_set_broadcast;
+ rtnl_link_set_carrier;
+ rtnl_link_set_family;
+ rtnl_link_set_flags;
+ rtnl_link_set_group;
+ rtnl_link_set_ifalias;
+ rtnl_link_set_ifindex;
+ rtnl_link_set_info_type;
+ rtnl_link_set_link;
+ rtnl_link_set_linkmode;
+ rtnl_link_set_master;
+ rtnl_link_set_mtu;
+ rtnl_link_set_name;
+ rtnl_link_set_ns_fd;
+ rtnl_link_set_ns_pid;
+ rtnl_link_set_num_rx_queues;
+ rtnl_link_set_num_tx_queues;
+ rtnl_link_set_operstate;
+ rtnl_link_set_promiscuity;
+ rtnl_link_set_qdisc;
+ rtnl_link_set_stat;
+ rtnl_link_set_txqlen;
+ rtnl_link_set_type;
+ rtnl_link_set_weight;
+ rtnl_link_sit_add;
+ rtnl_link_sit_alloc;
+ rtnl_link_sit_get_flags;
+ rtnl_link_sit_get_link;
+ rtnl_link_sit_get_local;
+ rtnl_link_sit_get_pmtudisc;
+ rtnl_link_sit_get_proto;
+ rtnl_link_sit_get_remote;
+ rtnl_link_sit_get_tos;
+ rtnl_link_sit_get_ttl;
+ rtnl_link_sit_set_flags;
+ rtnl_link_sit_set_link;
+ rtnl_link_sit_set_local;
+ rtnl_link_sit_set_pmtudisc;
+ rtnl_link_sit_set_proto;
+ rtnl_link_sit_set_remote;
+ rtnl_link_sit_set_tos;
+ rtnl_link_sit_set_ttl;
+ rtnl_link_stat2str;
+ rtnl_link_str2carrier;
+ rtnl_link_str2flags;
+ rtnl_link_str2mode;
+ rtnl_link_str2operstate;
+ rtnl_link_str2stat;
+ rtnl_link_unset_flags;
+ rtnl_link_veth_add;
+ rtnl_link_veth_alloc;
+ rtnl_link_veth_get_peer;
+ rtnl_link_veth_release;
+ rtnl_link_vlan_alloc;
+ rtnl_link_vlan_flags2str;
+ rtnl_link_vlan_get_egress_map;
+ rtnl_link_vlan_get_flags;
+ rtnl_link_vlan_get_id;
+ rtnl_link_vlan_get_ingress_map;
+ rtnl_link_vlan_get_protocol;
+ rtnl_link_vlan_set_egress_map;
+ rtnl_link_vlan_set_flags;
+ rtnl_link_vlan_set_id;
+ rtnl_link_vlan_set_ingress_map;
+ rtnl_link_vlan_set_protocol;
+ rtnl_link_vlan_str2flags;
+ rtnl_link_vlan_unset_flags;
+ rtnl_link_vxlan_alloc;
+ rtnl_link_vxlan_disable_l2miss;
+ rtnl_link_vxlan_disable_l3miss;
+ rtnl_link_vxlan_disable_learning;
+ rtnl_link_vxlan_disable_proxy;
+ rtnl_link_vxlan_disable_rsc;
+ rtnl_link_vxlan_enable_l2miss;
+ rtnl_link_vxlan_enable_l3miss;
+ rtnl_link_vxlan_enable_learning;
+ rtnl_link_vxlan_enable_proxy;
+ rtnl_link_vxlan_enable_rsc;
+ rtnl_link_vxlan_get_ageing;
+ rtnl_link_vxlan_get_group;
+ rtnl_link_vxlan_get_id;
+ rtnl_link_vxlan_get_l2miss;
+ rtnl_link_vxlan_get_l3miss;
+ rtnl_link_vxlan_get_learning;
+ rtnl_link_vxlan_get_limit;
+ rtnl_link_vxlan_get_link;
+ rtnl_link_vxlan_get_local;
+ rtnl_link_vxlan_get_port_range;
+ rtnl_link_vxlan_get_proxy;
+ rtnl_link_vxlan_get_rsc;
+ rtnl_link_vxlan_get_tos;
+ rtnl_link_vxlan_get_ttl;
+ rtnl_link_vxlan_set_ageing;
+ rtnl_link_vxlan_set_group;
+ rtnl_link_vxlan_set_id;
+ rtnl_link_vxlan_set_l2miss;
+ rtnl_link_vxlan_set_l3miss;
+ rtnl_link_vxlan_set_learning;
+ rtnl_link_vxlan_set_limit;
+ rtnl_link_vxlan_set_link;
+ rtnl_link_vxlan_set_local;
+ rtnl_link_vxlan_set_port_range;
+ rtnl_link_vxlan_set_proxy;
+ rtnl_link_vxlan_set_rsc;
+ rtnl_link_vxlan_set_tos;
+ rtnl_link_vxlan_set_ttl;
+ rtnl_meta_value_alloc_id;
+ rtnl_meta_value_alloc_int;
+ rtnl_meta_value_alloc_var;
+ rtnl_meta_value_put;
+ rtnl_mirred_get_action;
+ rtnl_mirred_get_ifindex;
+ rtnl_mirred_get_policy;
+ rtnl_mirred_set_action;
+ rtnl_mirred_set_ifindex;
+ rtnl_mirred_set_policy;
+ rtnl_neigh_add;
+ rtnl_neigh_alloc;
+ rtnl_neigh_alloc_cache;
+ rtnl_neigh_build_add_request;
+ rtnl_neigh_build_delete_request;
+ rtnl_neigh_delete;
+ rtnl_neigh_flags2str;
+ rtnl_neigh_get;
+ rtnl_neigh_get_dst;
+ rtnl_neigh_get_family;
+ rtnl_neigh_get_flags;
+ rtnl_neigh_get_ifindex;
+ rtnl_neigh_get_lladdr;
+ rtnl_neigh_get_state;
+ rtnl_neigh_get_type;
+ rtnl_neigh_parse;
+ rtnl_neigh_put;
+ rtnl_neigh_set_dst;
+ rtnl_neigh_set_family;
+ rtnl_neigh_set_flags;
+ rtnl_neigh_set_ifindex;
+ rtnl_neigh_set_lladdr;
+ rtnl_neigh_set_state;
+ rtnl_neigh_set_type;
+ rtnl_neigh_state2str;
+ rtnl_neigh_str2flag;
+ rtnl_neigh_str2state;
+ rtnl_neigh_unset_flags;
+ rtnl_neigh_unset_state;
+ rtnl_neightbl_alloc;
+ rtnl_neightbl_alloc_cache;
+ rtnl_neightbl_build_change_request;
+ rtnl_neightbl_change;
+ rtnl_neightbl_get;
+ rtnl_neightbl_put;
+ rtnl_neightbl_set_anycast_delay;
+ rtnl_neightbl_set_app_probes;
+ rtnl_neightbl_set_base_reachable_time;
+ rtnl_neightbl_set_delay_probe_time;
+ rtnl_neightbl_set_dev;
+ rtnl_neightbl_set_family;
+ rtnl_neightbl_set_gc_interval;
+ rtnl_neightbl_set_gc_stale_time;
+ rtnl_neightbl_set_gc_tresh1;
+ rtnl_neightbl_set_gc_tresh2;
+ rtnl_neightbl_set_gc_tresh3;
+ rtnl_neightbl_set_locktime;
+ rtnl_neightbl_set_mcast_probes;
+ rtnl_neightbl_set_name;
+ rtnl_neightbl_set_proxy_delay;
+ rtnl_neightbl_set_proxy_queue_len;
+ rtnl_neightbl_set_queue_len;
+ rtnl_neightbl_set_retrans_time;
+ rtnl_neightbl_set_ucast_probes;
+ rtnl_netem_get_corruption_correlation;
+ rtnl_netem_get_corruption_probability;
+ rtnl_netem_get_delay;
+ rtnl_netem_get_delay_correlation;
+ rtnl_netem_get_delay_distribution;
+ rtnl_netem_get_delay_distribution_size;
+ rtnl_netem_get_duplicate;
+ rtnl_netem_get_duplicate_correlation;
+ rtnl_netem_get_gap;
+ rtnl_netem_get_jitter;
+ rtnl_netem_get_limit;
+ rtnl_netem_get_loss;
+ rtnl_netem_get_loss_correlation;
+ rtnl_netem_get_reorder_correlation;
+ rtnl_netem_get_reorder_probability;
+ rtnl_netem_set_corruption_correlation;
+ rtnl_netem_set_corruption_probability;
+ rtnl_netem_set_delay;
+ rtnl_netem_set_delay_correlation;
+ rtnl_netem_set_delay_distribution;
+ rtnl_netem_set_duplicate;
+ rtnl_netem_set_duplicate_correlation;
+ rtnl_netem_set_gap;
+ rtnl_netem_set_jitter;
+ rtnl_netem_set_limit;
+ rtnl_netem_set_loss;
+ rtnl_netem_set_loss_correlation;
+ rtnl_netem_set_reorder_correlation;
+ rtnl_netem_set_reorder_probability;
+ rtnl_pktloc_add;
+ rtnl_pktloc_alloc;
+ rtnl_pktloc_foreach;
+ rtnl_pktloc_lookup;
+ rtnl_pktloc_put;
+ rtnl_prio2str;
+ rtnl_qdisc_add;
+ rtnl_qdisc_alloc;
+ rtnl_qdisc_alloc_cache;
+ rtnl_qdisc_build_add_request;
+ rtnl_qdisc_build_change_request;
+ rtnl_qdisc_build_delete_request;
+ rtnl_qdisc_build_update_request;
+ rtnl_qdisc_change;
+ rtnl_qdisc_delete;
+ rtnl_qdisc_dsmark_get_default_index;
+ rtnl_qdisc_dsmark_get_indices;
+ rtnl_qdisc_dsmark_get_set_tc_index;
+ rtnl_qdisc_dsmark_set_default_index;
+ rtnl_qdisc_dsmark_set_indices;
+ rtnl_qdisc_dsmark_set_set_tc_index;
+ rtnl_qdisc_fifo_get_limit;
+ rtnl_qdisc_fifo_set_limit;
+ rtnl_qdisc_foreach_child;
+ rtnl_qdisc_foreach_cls;
+ rtnl_qdisc_fq_codel_get_ecn;
+ rtnl_qdisc_fq_codel_get_flows;
+ rtnl_qdisc_fq_codel_get_interval;
+ rtnl_qdisc_fq_codel_get_limit;
+ rtnl_qdisc_fq_codel_get_quantum;
+ rtnl_qdisc_fq_codel_get_target;
+ rtnl_qdisc_fq_codel_set_ecn;
+ rtnl_qdisc_fq_codel_set_flows;
+ rtnl_qdisc_fq_codel_set_interval;
+ rtnl_qdisc_fq_codel_set_limit;
+ rtnl_qdisc_fq_codel_set_quantum;
+ rtnl_qdisc_fq_codel_set_target;
+ rtnl_qdisc_get;
+ rtnl_qdisc_get_by_parent;
+ rtnl_qdisc_plug_buffer;
+ rtnl_qdisc_plug_release_indefinite;
+ rtnl_qdisc_plug_release_one;
+ rtnl_qdisc_plug_set_limit;
+ rtnl_qdisc_prio_get_bands;
+ rtnl_qdisc_prio_get_priomap;
+ rtnl_qdisc_prio_set_bands;
+ rtnl_qdisc_prio_set_priomap;
+ rtnl_qdisc_put;
+ rtnl_qdisc_tbf_get_limit;
+ rtnl_qdisc_tbf_get_peakrate;
+ rtnl_qdisc_tbf_get_peakrate_bucket;
+ rtnl_qdisc_tbf_get_peakrate_cell;
+ rtnl_qdisc_tbf_get_rate;
+ rtnl_qdisc_tbf_get_rate_bucket;
+ rtnl_qdisc_tbf_get_rate_cell;
+ rtnl_qdisc_tbf_set_limit;
+ rtnl_qdisc_tbf_set_limit_by_latency;
+ rtnl_qdisc_tbf_set_peakrate;
+ rtnl_qdisc_tbf_set_rate;
+ rtnl_qdisc_update;
+ rtnl_realms2str;
+ rtnl_red_get_limit;
+ rtnl_red_set_limit;
+ rtnl_route_add;
+ rtnl_route_add_nexthop;
+ rtnl_route_alloc;
+ rtnl_route_alloc_cache;
+ rtnl_route_build_add_request;
+ rtnl_route_build_del_request;
+ rtnl_route_build_msg;
+ rtnl_route_delete;
+ rtnl_route_foreach_nexthop;
+ rtnl_route_get;
+ rtnl_route_get_dst;
+ rtnl_route_get_family;
+ rtnl_route_get_flags;
+ rtnl_route_get_iif;
+ rtnl_route_get_metric;
+ rtnl_route_get_nexthops;
+ rtnl_route_get_nnexthops;
+ rtnl_route_get_pref_src;
+ rtnl_route_get_priority;
+ rtnl_route_get_protocol;
+ rtnl_route_get_scope;
+ rtnl_route_get_src;
+ rtnl_route_get_table;
+ rtnl_route_get_tos;
+ rtnl_route_get_type;
+ rtnl_route_guess_scope;
+ rtnl_route_metric2str;
+ rtnl_route_nexthop_n;
+ rtnl_route_nh_alloc;
+ rtnl_route_nh_clone;
+ rtnl_route_nh_compare;
+ rtnl_route_nh_dump;
+ rtnl_route_nh_flags2str;
+ rtnl_route_nh_free;
+ rtnl_route_nh_get_flags;
+ rtnl_route_nh_get_gateway;
+ rtnl_route_nh_get_ifindex;
+ rtnl_route_nh_get_realms;
+ rtnl_route_nh_get_weight;
+ rtnl_route_nh_set_flags;
+ rtnl_route_nh_set_gateway;
+ rtnl_route_nh_set_ifindex;
+ rtnl_route_nh_set_realms;
+ rtnl_route_nh_set_weight;
+ rtnl_route_nh_str2flags;
+ rtnl_route_nh_unset_flags;
+ rtnl_route_parse;
+ rtnl_route_proto2str;
+ rtnl_route_put;
+ rtnl_route_read_protocol_names;
+ rtnl_route_read_table_names;
+ rtnl_route_remove_nexthop;
+ rtnl_route_set_dst;
+ rtnl_route_set_family;
+ rtnl_route_set_flags;
+ rtnl_route_set_iif;
+ rtnl_route_set_metric;
+ rtnl_route_set_pref_src;
+ rtnl_route_set_priority;
+ rtnl_route_set_protocol;
+ rtnl_route_set_scope;
+ rtnl_route_set_src;
+ rtnl_route_set_table;
+ rtnl_route_set_tos;
+ rtnl_route_set_type;
+ rtnl_route_str2metric;
+ rtnl_route_str2proto;
+ rtnl_route_str2table;
+ rtnl_route_table2str;
+ rtnl_route_unset_flags;
+ rtnl_route_unset_metric;
+ rtnl_rule_add;
+ rtnl_rule_alloc;
+ rtnl_rule_alloc_cache;
+ rtnl_rule_build_add_request;
+ rtnl_rule_build_delete_request;
+ rtnl_rule_delete;
+ rtnl_rule_get_action;
+ rtnl_rule_get_dsfield;
+ rtnl_rule_get_dst;
+ rtnl_rule_get_family;
+ rtnl_rule_get_goto;
+ rtnl_rule_get_iif;
+ rtnl_rule_get_mark;
+ rtnl_rule_get_mask;
+ rtnl_rule_get_oif;
+ rtnl_rule_get_prio;
+ rtnl_rule_get_realms;
+ rtnl_rule_get_src;
+ rtnl_rule_get_table;
+ rtnl_rule_put;
+ rtnl_rule_set_action;
+ rtnl_rule_set_dsfield;
+ rtnl_rule_set_dst;
+ rtnl_rule_set_family;
+ rtnl_rule_set_goto;
+ rtnl_rule_set_iif;
+ rtnl_rule_set_mark;
+ rtnl_rule_set_mask;
+ rtnl_rule_set_oif;
+ rtnl_rule_set_prio;
+ rtnl_rule_set_realms;
+ rtnl_rule_set_src;
+ rtnl_rule_set_table;
+ rtnl_scope2str;
+ rtnl_sfq_get_divisor;
+ rtnl_sfq_get_limit;
+ rtnl_sfq_get_perturb;
+ rtnl_sfq_get_quantum;
+ rtnl_sfq_set_limit;
+ rtnl_sfq_set_perturb;
+ rtnl_sfq_set_quantum;
+ rtnl_str2prio;
+ rtnl_str2scope;
+ rtnl_tc_calc_bufsize;
+ rtnl_tc_calc_cell_log;
+ rtnl_tc_calc_txtime;
+ rtnl_tc_get_handle;
+ rtnl_tc_get_ifindex;
+ rtnl_tc_get_kind;
+ rtnl_tc_get_link;
+ rtnl_tc_get_linktype;
+ rtnl_tc_get_mpu;
+ rtnl_tc_get_mtu;
+ rtnl_tc_get_overhead;
+ rtnl_tc_get_parent;
+ rtnl_tc_get_stat;
+ rtnl_tc_handle2str;
+ rtnl_tc_read_classid_file;
+ rtnl_tc_set_handle;
+ rtnl_tc_set_ifindex;
+ rtnl_tc_set_kind;
+ rtnl_tc_set_link;
+ rtnl_tc_set_linktype;
+ rtnl_tc_set_mpu;
+ rtnl_tc_set_mtu;
+ rtnl_tc_set_overhead;
+ rtnl_tc_set_parent;
+ rtnl_tc_str2handle;
+ rtnl_u32_add_action;
+ rtnl_u32_add_key;
+ rtnl_u32_add_key_in6_addr;
+ rtnl_u32_add_key_in_addr;
+ rtnl_u32_add_key_uint16;
+ rtnl_u32_add_key_uint32;
+ rtnl_u32_add_key_uint8;
+ rtnl_u32_del_action;
+ rtnl_u32_get_key;
+ rtnl_u32_set_classid;
+ rtnl_u32_set_cls_terminal;
+ rtnl_u32_set_divisor;
+ rtnl_u32_set_flags;
+ rtnl_u32_set_handle;
+ rtnl_u32_set_hashmask;
+ rtnl_u32_set_hashtable;
+ rtnl_u32_set_link;
+
+ # The following symbols were added during the development of 3.2.26.
+ # Keep them in libnl_3 to avoid breaking users.
+ rtnl_class_hfsc_get_fsc;
+ rtnl_class_hfsc_get_rsc;
+ rtnl_class_hfsc_get_usc;
+ rtnl_class_hfsc_set_fsc;
+ rtnl_class_hfsc_set_rsc;
+ rtnl_class_hfsc_set_usc;
+ rtnl_link_inet6_addrgenmode2str;
+ rtnl_link_inet6_get_addr_gen_mode;
+ rtnl_link_inet6_get_token;
+ rtnl_link_inet6_set_addr_gen_mode;
+ rtnl_link_inet6_set_token;
+ rtnl_link_inet6_str2addrgenmode;
+ rtnl_qdisc_hfsc_get_defcls;
+ rtnl_qdisc_hfsc_set_defcls;
+ rtnl_u32_add_mark;
+ rtnl_u32_del_mark;
+
+local:
+ *;
+};
+
+libnl_3_2_26 {
+global:
+ rtnl_neigh_get_vlan;
+ rtnl_neigh_set_vlan;
+ rtnl_skbedit_get_action;
+ rtnl_skbedit_get_mark;
+ rtnl_skbedit_get_priority;
+ rtnl_skbedit_get_queue_mapping;
+ rtnl_skbedit_set_action;
+ rtnl_skbedit_set_mark;
+ rtnl_skbedit_set_priority;
+ rtnl_skbedit_set_queue_mapping;
+ rtnl_tc_stat2str;
+ rtnl_tc_str2stat;
+ rtnl_u32_get_classid;
+} libnl_3;
+
+libnl_3_2_27 {
+global:
+ rtnl_link_get_link_netnsid;
+ rtnl_link_ipvlan_alloc;
+ rtnl_link_is_ipvlan;
+ rtnl_link_ipvlan_mode2str;
+ rtnl_link_ipvlan_str2mode;
+ rtnl_link_ipvlan_set_mode;
+ rtnl_link_ipvlan_get_mode;
+ rtnl_link_set_link_netnsid;
+} libnl_3_2_26;
+
+libnl_3_2_28 {
+global:
+ rtnl_link_alloc_cache_flags;
+ rtnl_link_bridge_get_port_vlan;
+ rtnl_link_bridge_has_vlan;
+ rtnl_link_bridge_pvid;
+ rtnl_link_is_macvtap;
+ rtnl_link_is_vrf;
+ rtnl_link_ipgretap_add;
+ rtnl_link_ipgretap_alloc;
+ rtnl_link_macsec_alloc;
+ rtnl_link_macsec_set_sci;
+ rtnl_link_macsec_get_sci;
+ rtnl_link_macsec_set_port;
+ rtnl_link_macsec_get_port;
+ rtnl_link_macsec_set_cipher_suite;
+ rtnl_link_macsec_get_cipher_suite;
+ rtnl_link_macsec_set_icv_len;
+ rtnl_link_macsec_get_icv_len;
+ rtnl_link_macsec_set_protect;
+ rtnl_link_macsec_get_protect;
+ rtnl_link_macsec_set_encrypt;
+ rtnl_link_macsec_get_encrypt;
+ rtnl_link_macsec_set_encoding_sa;
+ rtnl_link_macsec_get_encoding_sa;
+ rtnl_link_macsec_set_validation_type;
+ rtnl_link_macsec_get_validation_type;
+ rtnl_link_macsec_set_replay_protect;
+ rtnl_link_macsec_get_replay_protect;
+ rtnl_link_macsec_set_window;
+ rtnl_link_macsec_get_window;
+ rtnl_link_macsec_set_send_sci;
+ rtnl_link_macsec_get_send_sci;
+ rtnl_link_macsec_set_end_station;
+ rtnl_link_macsec_get_end_station;
+ rtnl_link_macsec_set_scb;
+ rtnl_link_macsec_get_scb;
+ rtnl_link_macvtap_alloc;
+ rtnl_link_macvtap_flags2str;
+ rtnl_link_macvtap_get_flags;
+ rtnl_link_macvtap_get_mode;
+ rtnl_link_macvtap_mode2str;
+ rtnl_link_macvtap_set_flags;
+ rtnl_link_macvtap_set_mode;
+ rtnl_link_macvtap_str2flags;
+ rtnl_link_macvtap_str2mode;
+ rtnl_link_macvtap_unset_flags;
+ rtnl_link_sit_get_ip6rd_prefix;
+ rtnl_link_sit_get_ip6rd_prefixlen;
+ rtnl_link_sit_get_ip6rd_relay_prefix;
+ rtnl_link_sit_get_ip6rd_relay_prefixlen;
+ rtnl_link_sit_set_ip6rd_prefix;
+ rtnl_link_sit_set_ip6rd_prefixlen;
+ rtnl_link_sit_set_ip6rd_relay_prefix;
+ rtnl_link_sit_set_ip6rd_relay_prefixlen;
+ rtnl_link_vrf_alloc;
+ rtnl_link_vrf_get_tableid;
+ rtnl_link_vrf_set_tableid;
+ rtnl_neigh_alloc_cache_flags;
+} libnl_3_2_27;
+
+libnl_3_2_29 {
+global:
+ rtnl_gact_set_action;
+ rtnl_gact_get_action;
+ rtnl_link_bridge_portstate2str;
+ rtnl_link_bridge_str2portstate;
+ rtnl_link_bridge_set_self;
+ rtnl_link_bridge_get_hwmode;
+ rtnl_link_bridge_set_hwmode;
+ rtnl_link_bridge_hwmode2str;
+ rtnl_link_bridge_str2hwmode;
+ rtnl_link_get_carrier_changes;
+ rtnl_link_get_gso_max_segs;
+ rtnl_link_get_gso_max_size;
+ rtnl_link_get_phys_port_name;
+ rtnl_link_get_phys_switch_id;
+ rtnl_link_ipgre_get_pmtudisc;
+ rtnl_link_is_ipgretap;
+ rtnl_link_macvlan_add_macaddr;
+ rtnl_link_macvlan_count_macaddr;
+ rtnl_link_macvlan_del_macaddr;
+ rtnl_link_macvlan_get_macaddr;
+ rtnl_link_macvlan_get_macmode;
+ rtnl_link_macvlan_macmode2str;
+ rtnl_link_macvlan_set_macmode;
+ rtnl_link_macvlan_str2macmode;
+ rtnl_link_ppp_alloc;
+ rtnl_link_ppp_set_fd;
+ rtnl_link_ppp_get_fd;
+ rtnl_link_vxlan_get_collect_metadata;
+ rtnl_link_vxlan_get_flags;
+ rtnl_link_vxlan_get_label;
+ rtnl_link_vxlan_get_port;
+ rtnl_link_vxlan_get_remcsum_rx;
+ rtnl_link_vxlan_get_remcsum_tx;
+ rtnl_link_vxlan_get_udp_csum;
+ rtnl_link_vxlan_get_udp_zero_csum6_rx;
+ rtnl_link_vxlan_get_udp_zero_csum6_tx;
+ rtnl_link_vxlan_set_collect_metadata;
+ rtnl_link_vxlan_set_flags;
+ rtnl_link_vxlan_set_label;
+ rtnl_link_vxlan_set_port;
+ rtnl_link_vxlan_set_remcsum_rx;
+ rtnl_link_vxlan_set_remcsum_tx;
+ rtnl_link_vxlan_set_udp_csum;
+ rtnl_link_vxlan_set_udp_zero_csum6_rx;
+ rtnl_link_vxlan_set_udp_zero_csum6_tx;
+ rtnl_link_has_vf_list;
+ rtnl_link_set_vf_list;
+ rtnl_link_unset_vf_list;
+ rtnl_link_vf_add;
+ rtnl_link_vf_alloc;
+ rtnl_link_vf_free;
+ rtnl_link_vf_get;
+ rtnl_link_vf_put;
+ rtnl_link_vf_get_addr;
+ rtnl_link_vf_set_addr;
+ rtnl_link_vf_set_ib_node_guid;
+ rtnl_link_vf_set_ib_port_guid;
+ rtnl_link_vf_get_index;
+ rtnl_link_vf_set_index;
+ rtnl_link_vf_get_linkstate;
+ rtnl_link_vf_set_linkstate;
+ rtnl_link_vf_get_rate;
+ rtnl_link_vf_set_rate;
+ rtnl_link_vf_get_rss_query_en;
+ rtnl_link_vf_set_rss_query_en;
+ rtnl_link_vf_get_spoofchk;
+ rtnl_link_vf_set_spoofchk;
+ rtnl_link_vf_get_stat;
+ rtnl_link_vf_get_trust;
+ rtnl_link_vf_set_trust;
+ rtnl_link_vf_get_vlans;
+ rtnl_link_vf_set_vlans;
+ rtnl_link_vf_vlan_alloc;
+ rtnl_link_vf_vlan_free;
+ rtnl_link_vf_vlan_put;
+ rtnl_link_vf_linkstate2str;
+ rtnl_link_vf_str2linkstate;
+ rtnl_link_vf_vlanproto2str;
+ rtnl_link_vf_str2vlanproto;
+ rtnl_link_vf_str2guid;
+ rtnl_u32_set_selector;
+} libnl_3_2_28;
+
+libnl_3_4 {
+global:
+ rtnl_act_next;
+ rtnl_basic_get_action;
+ rtnl_link_inet6_flags2str;
+ rtnl_link_inet6_get_flags;
+ rtnl_link_inet6_set_flags;
+ rtnl_link_inet6_str2flags;
+ rtnl_netconf_get_all;
+ rtnl_netconf_get_by_idx;
+ rtnl_netconf_get_default;
+ rtnl_netconf_get_family;
+ rtnl_netconf_get_forwarding;
+ rtnl_netconf_get_ifindex;
+ rtnl_netconf_get_input;
+ rtnl_netconf_get_mc_forwarding;
+ rtnl_netconf_get_rp_filter;
+ rtnl_netconf_put;
+ rtnl_rule_get_l3mdev;
+ rtnl_rule_set_l3mdev;
+ rtnl_u32_get_action;
+ rtnl_route_nh_set_newdst;
+ rtnl_route_nh_get_newdst;
+ rtnl_route_nh_set_via;
+ rtnl_route_nh_get_via;
+ rtnl_route_set_ttl_propagate;
+ rtnl_route_get_ttl_propagate;
+ rtnl_route_nh_encap_mpls;
+} libnl_3_2_29;
+
+libnl_3_5 {
+global:
+ rtnl_class_get_by_parent;
+ rtnl_cls_cache_set_tc_params;
+ rtnl_ematch_tree_clone;
+ rtnl_htb_get_ceil64;
+ rtnl_htb_get_rate64;
+ rtnl_htb_set_ceil64;
+ rtnl_htb_set_rate64;
+ rtnl_link_geneve_alloc;
+ rtnl_link_geneve_get_flags;
+ rtnl_link_geneve_get_id;
+ rtnl_link_geneve_get_label;
+ rtnl_link_geneve_get_port;
+ rtnl_link_geneve_get_remote;
+ rtnl_link_geneve_get_tos;
+ rtnl_link_geneve_get_ttl;
+ rtnl_link_geneve_get_udp_csum;
+ rtnl_link_geneve_get_udp_zero_csum6_rx;
+ rtnl_link_geneve_get_udp_zero_csum6_tx;
+ rtnl_link_geneve_set_flags;
+ rtnl_link_geneve_set_id;
+ rtnl_link_geneve_set_label;
+ rtnl_link_geneve_set_port;
+ rtnl_link_geneve_set_remote;
+ rtnl_link_geneve_set_tos;
+ rtnl_link_geneve_set_ttl;
+ rtnl_link_geneve_set_udp_csum;
+ rtnl_link_geneve_set_udp_zero_csum6_rx;
+ rtnl_link_geneve_set_udp_zero_csum6_tx;
+ rtnl_link_get_slave_type;
+ rtnl_link_is_geneve;
+ rtnl_link_is_xfrmi;
+ rtnl_link_set_slave_type;
+ rtnl_link_xfrmi_alloc;
+ rtnl_link_xfrmi_get_if_id;
+ rtnl_link_xfrmi_get_link;
+ rtnl_link_xfrmi_set_if_id;
+ rtnl_link_xfrmi_set_link;
+ rtnl_mall_append_action;
+ rtnl_mall_del_action;
+ rtnl_mall_get_classid;
+ rtnl_mall_get_first_action;
+ rtnl_mall_get_flags;
+ rtnl_mall_set_classid;
+ rtnl_mall_set_flags;
+ rtnl_neigh_get_by_vlan;
+ rtnl_neigh_get_master;
+ rtnl_neigh_set_master;
+ rtnl_netem_set_delay_distribution_data;
+ rtnl_qdisc_mqprio_get_hw_offload;
+ rtnl_qdisc_mqprio_get_max_rate;
+ rtnl_qdisc_mqprio_get_min_rate;
+ rtnl_qdisc_mqprio_get_mode;
+ rtnl_qdisc_mqprio_get_num_tc;
+ rtnl_qdisc_mqprio_get_priomap;
+ rtnl_qdisc_mqprio_get_queue;
+ rtnl_qdisc_mqprio_get_shaper;
+ rtnl_qdisc_mqprio_hw_offload;
+ rtnl_qdisc_mqprio_set_max_rate;
+ rtnl_qdisc_mqprio_set_min_rate;
+ rtnl_qdisc_mqprio_set_mode;
+ rtnl_qdisc_mqprio_set_num_tc;
+ rtnl_qdisc_mqprio_set_priomap;
+ rtnl_qdisc_mqprio_set_queue;
+ rtnl_qdisc_mqprio_set_shaper;
+ rtnl_rule_get_dport;
+ rtnl_rule_get_ipproto;
+ rtnl_rule_get_protocol;
+ rtnl_rule_get_sport;
+ rtnl_rule_set_dport;
+ rtnl_rule_set_dport_range;
+ rtnl_rule_set_ipproto;
+ rtnl_rule_set_protocol;
+ rtnl_rule_set_sport;
+ rtnl_rule_set_sport_range;
+ rtnl_tc_get_chain;
+ rtnl_tc_set_chain;
+ rtnl_vlan_get_action;
+ rtnl_vlan_get_mode;
+ rtnl_vlan_get_protocol;
+ rtnl_vlan_get_vlan_id;
+ rtnl_vlan_get_vlan_prio;
+ rtnl_vlan_set_action;
+ rtnl_vlan_set_mode;
+ rtnl_vlan_set_protocol;
+ rtnl_vlan_set_vlan_id;
+ rtnl_vlan_set_vlan_prio;
+} libnl_3_4;
diff --git a/libnl-xfrm-3.0.pc.in b/libnl-xfrm-3.0.pc.in
new file mode 100644
index 00000000..48ffb704
--- /dev/null
+++ b/libnl-xfrm-3.0.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libnl-xfrm
+Description: Netlink Routing Family Library
+Version: @PACKAGE_VERSION@
+Requires: libnl-3.0
+Libs: -L${libdir} -lnl-xfrm-@MAJ_VERSION@
+Cflags: -I${includedir}/libnl@MAJ_VERSION@
diff --git a/libnl-xfrm-3.sym b/libnl-xfrm-3.sym
new file mode 100644
index 00000000..3706f33d
--- /dev/null
+++ b/libnl-xfrm-3.sym
@@ -0,0 +1,246 @@
+libnl_3 {
+global:
+ xfrmnl_ae_alloc;
+ xfrmnl_ae_build_get_request;
+ xfrmnl_ae_flags2str;
+ xfrmnl_ae_get_curlifetime;
+ xfrmnl_ae_get_daddr;
+ xfrmnl_ae_get_family;
+ xfrmnl_ae_get_flags;
+ xfrmnl_ae_get_kernel;
+ xfrmnl_ae_get_mark;
+ xfrmnl_ae_get_proto;
+ xfrmnl_ae_get_replay_maxage;
+ xfrmnl_ae_get_replay_maxdiff;
+ xfrmnl_ae_get_replay_state;
+ xfrmnl_ae_get_replay_state_esn;
+ xfrmnl_ae_get_reqid;
+ xfrmnl_ae_get_saddr;
+ xfrmnl_ae_get_spi;
+ xfrmnl_ae_parse;
+ xfrmnl_ae_put;
+ xfrmnl_ae_set;
+ xfrmnl_ae_set_curlifetime;
+ xfrmnl_ae_set_daddr;
+ xfrmnl_ae_set_family;
+ xfrmnl_ae_set_flags;
+ xfrmnl_ae_set_mark;
+ xfrmnl_ae_set_proto;
+ xfrmnl_ae_set_replay_maxage;
+ xfrmnl_ae_set_replay_maxdiff;
+ xfrmnl_ae_set_replay_state;
+ xfrmnl_ae_set_replay_state_esn;
+ xfrmnl_ae_set_reqid;
+ xfrmnl_ae_set_saddr;
+ xfrmnl_ae_set_spi;
+ xfrmnl_ae_str2flag;
+ xfrmnl_ltime_cfg_alloc;
+ xfrmnl_ltime_cfg_clone;
+ xfrmnl_ltime_cfg_cmp;
+ xfrmnl_ltime_cfg_get;
+ xfrmnl_ltime_cfg_get_hard_addexpires;
+ xfrmnl_ltime_cfg_get_hard_bytelimit;
+ xfrmnl_ltime_cfg_get_hard_packetlimit;
+ xfrmnl_ltime_cfg_get_hard_useexpires;
+ xfrmnl_ltime_cfg_get_soft_addexpires;
+ xfrmnl_ltime_cfg_get_soft_bytelimit;
+ xfrmnl_ltime_cfg_get_soft_packetlimit;
+ xfrmnl_ltime_cfg_get_soft_useexpires;
+ xfrmnl_ltime_cfg_put;
+ xfrmnl_ltime_cfg_set_hard_addexpires;
+ xfrmnl_ltime_cfg_set_hard_bytelimit;
+ xfrmnl_ltime_cfg_set_hard_packetlimit;
+ xfrmnl_ltime_cfg_set_hard_useexpires;
+ xfrmnl_ltime_cfg_set_soft_addexpires;
+ xfrmnl_ltime_cfg_set_soft_bytelimit;
+ xfrmnl_ltime_cfg_set_soft_packetlimit;
+ xfrmnl_ltime_cfg_set_soft_useexpires;
+ xfrmnl_ltime_cfg_shared;
+ xfrmnl_sa_add;
+ xfrmnl_sa_alloc;
+ xfrmnl_sa_alloc_cache;
+ xfrmnl_sa_build_add_request;
+ xfrmnl_sa_build_delete_request;
+ xfrmnl_sa_build_get_request;
+ xfrmnl_sa_build_update_request;
+ xfrmnl_sa_delete;
+ xfrmnl_sa_flags2str;
+ xfrmnl_sa_get;
+ xfrmnl_sa_get_aead_params;
+ xfrmnl_sa_get_auth_params;
+ xfrmnl_sa_get_coaddr;
+ xfrmnl_sa_get_comp_params;
+ xfrmnl_sa_get_crypto_params;
+ xfrmnl_sa_get_curlifetime;
+ xfrmnl_sa_get_daddr;
+ xfrmnl_sa_get_encap_tmpl;
+ xfrmnl_sa_get_family;
+ xfrmnl_sa_get_flags;
+ xfrmnl_sa_get_kernel;
+ xfrmnl_sa_get_lifetime_cfg;
+ xfrmnl_sa_get_mark;
+ xfrmnl_sa_get_mode;
+ xfrmnl_sa_get_proto;
+ xfrmnl_sa_get_replay_maxage;
+ xfrmnl_sa_get_replay_maxdiff;
+ xfrmnl_sa_get_replay_state;
+ xfrmnl_sa_get_replay_state_esn;
+ xfrmnl_sa_get_replay_window;
+ xfrmnl_sa_get_reqid;
+ xfrmnl_sa_get_saddr;
+ xfrmnl_sa_get_sec_ctx;
+ xfrmnl_sa_get_sel;
+ xfrmnl_sa_get_seq;
+ xfrmnl_sa_get_spi;
+ xfrmnl_sa_get_stats;
+ xfrmnl_sa_get_tfcpad;
+ xfrmnl_sa_is_expiry_reached;
+ xfrmnl_sa_is_hardexpiry_reached;
+ xfrmnl_sa_mode2str;
+ xfrmnl_sa_parse;
+ xfrmnl_sa_put;
+ xfrmnl_sa_set_aead_params;
+ xfrmnl_sa_set_auth_params;
+ xfrmnl_sa_set_coaddr;
+ xfrmnl_sa_set_comp_params;
+ xfrmnl_sa_set_crypto_params;
+ xfrmnl_sa_set_daddr;
+ xfrmnl_sa_set_encap_tmpl;
+ xfrmnl_sa_set_family;
+ xfrmnl_sa_set_flags;
+ xfrmnl_sa_set_lifetime_cfg;
+ xfrmnl_sa_set_mark;
+ xfrmnl_sa_set_mode;
+ xfrmnl_sa_set_proto;
+ xfrmnl_sa_set_replay_maxage;
+ xfrmnl_sa_set_replay_maxdiff;
+ xfrmnl_sa_set_replay_state;
+ xfrmnl_sa_set_replay_state_esn;
+ xfrmnl_sa_set_replay_window;
+ xfrmnl_sa_set_reqid;
+ xfrmnl_sa_set_saddr;
+ xfrmnl_sa_set_sec_ctx;
+ xfrmnl_sa_set_sel;
+ xfrmnl_sa_set_spi;
+ xfrmnl_sa_set_tfcpad;
+ xfrmnl_sa_str2flag;
+ xfrmnl_sa_str2mode;
+ xfrmnl_sa_update;
+ xfrmnl_sel_alloc;
+ xfrmnl_sel_clone;
+ xfrmnl_sel_cmp;
+ xfrmnl_sel_dump;
+ xfrmnl_sel_get;
+ xfrmnl_sel_get_daddr;
+ xfrmnl_sel_get_dport;
+ xfrmnl_sel_get_dportmask;
+ xfrmnl_sel_get_family;
+ xfrmnl_sel_get_ifindex;
+ xfrmnl_sel_get_prefixlen_d;
+ xfrmnl_sel_get_prefixlen_s;
+ xfrmnl_sel_get_proto;
+ xfrmnl_sel_get_saddr;
+ xfrmnl_sel_get_sport;
+ xfrmnl_sel_get_sportmask;
+ xfrmnl_sel_get_userid;
+ xfrmnl_sel_put;
+ xfrmnl_sel_set_daddr;
+ xfrmnl_sel_set_dport;
+ xfrmnl_sel_set_dportmask;
+ xfrmnl_sel_set_family;
+ xfrmnl_sel_set_ifindex;
+ xfrmnl_sel_set_prefixlen_d;
+ xfrmnl_sel_set_prefixlen_s;
+ xfrmnl_sel_set_proto;
+ xfrmnl_sel_set_saddr;
+ xfrmnl_sel_set_sport;
+ xfrmnl_sel_set_sportmask;
+ xfrmnl_sel_set_userid;
+ xfrmnl_sel_shared;
+ xfrmnl_sp_action2str;
+ xfrmnl_sp_add;
+ xfrmnl_sp_add_usertemplate;
+ xfrmnl_sp_alloc;
+ xfrmnl_sp_alloc_cache;
+ xfrmnl_sp_build_add_request;
+ xfrmnl_sp_build_delete_request;
+ xfrmnl_sp_build_get_request;
+ xfrmnl_sp_build_update_request;
+ xfrmnl_sp_delete;
+ xfrmnl_sp_dir2str;
+ xfrmnl_sp_flags2str;
+ xfrmnl_sp_foreach_usertemplate;
+ xfrmnl_sp_get;
+ xfrmnl_sp_get_action;
+ xfrmnl_sp_get_curlifetime;
+ xfrmnl_sp_get_dir;
+ xfrmnl_sp_get_flags;
+ xfrmnl_sp_get_index;
+ xfrmnl_sp_get_kernel;
+ xfrmnl_sp_get_lifetime_cfg;
+ xfrmnl_sp_get_mark;
+ xfrmnl_sp_get_nusertemplates;
+ xfrmnl_sp_get_priority;
+ xfrmnl_sp_get_sec_ctx;
+ xfrmnl_sp_get_sel;
+ xfrmnl_sp_get_share;
+ xfrmnl_sp_get_userpolicy_type;
+ xfrmnl_sp_get_usertemplates;
+ xfrmnl_sp_index2dir;
+ xfrmnl_sp_parse;
+ xfrmnl_sp_put;
+ xfrmnl_sp_remove_usertemplate;
+ xfrmnl_sp_set_action;
+ xfrmnl_sp_set_dir;
+ xfrmnl_sp_set_flags;
+ xfrmnl_sp_set_index;
+ xfrmnl_sp_set_lifetime_cfg;
+ xfrmnl_sp_set_mark;
+ xfrmnl_sp_set_priority;
+ xfrmnl_sp_set_sec_ctx;
+ xfrmnl_sp_set_sel;
+ xfrmnl_sp_set_share;
+ xfrmnl_sp_set_userpolicy_type;
+ xfrmnl_sp_share2str;
+ xfrmnl_sp_str2action;
+ xfrmnl_sp_str2dir;
+ xfrmnl_sp_str2flag;
+ xfrmnl_sp_str2share;
+ xfrmnl_sp_str2type;
+ xfrmnl_sp_type2str;
+ xfrmnl_sp_update;
+ xfrmnl_sp_usertemplate_n;
+ xfrmnl_user_tmpl_alloc;
+ xfrmnl_user_tmpl_clone;
+ xfrmnl_user_tmpl_cmp;
+ xfrmnl_user_tmpl_dump;
+ xfrmnl_user_tmpl_free;
+ xfrmnl_user_tmpl_get_aalgos;
+ xfrmnl_user_tmpl_get_calgos;
+ xfrmnl_user_tmpl_get_daddr;
+ xfrmnl_user_tmpl_get_ealgos;
+ xfrmnl_user_tmpl_get_family;
+ xfrmnl_user_tmpl_get_mode;
+ xfrmnl_user_tmpl_get_optional;
+ xfrmnl_user_tmpl_get_proto;
+ xfrmnl_user_tmpl_get_reqid;
+ xfrmnl_user_tmpl_get_saddr;
+ xfrmnl_user_tmpl_get_share;
+ xfrmnl_user_tmpl_get_spi;
+ xfrmnl_user_tmpl_mode2str;
+ xfrmnl_user_tmpl_set_aalgos;
+ xfrmnl_user_tmpl_set_calgos;
+ xfrmnl_user_tmpl_set_daddr;
+ xfrmnl_user_tmpl_set_ealgos;
+ xfrmnl_user_tmpl_set_family;
+ xfrmnl_user_tmpl_set_mode;
+ xfrmnl_user_tmpl_set_optional;
+ xfrmnl_user_tmpl_set_proto;
+ xfrmnl_user_tmpl_set_reqid;
+ xfrmnl_user_tmpl_set_saddr;
+ xfrmnl_user_tmpl_set_share;
+ xfrmnl_user_tmpl_set_spi;
+ xfrmnl_user_tmpl_str2mode;
+local:
+ *;
+};
diff --git a/libnl.sym.in b/libnl.sym.in
deleted file mode 100644
index df8888c6..00000000
--- a/libnl.sym.in
+++ /dev/null
@@ -1,9 +0,0 @@
-libnl_@MAJ_VERSION@ {
-global:
- *;
-local:
- _nl_socket_generate_local_port_no_release;
- _nl_socket_is_local_port_unspecified;
- _nl_socket_used_ports_release_all;
- _nl_socket_used_ports_set;
-};
diff --git a/m4/ax_pkg_swig.m4 b/m4/ax_pkg_swig.m4
deleted file mode 100644
index e112f3d3..00000000
--- a/m4/ax_pkg_swig.m4
+++ /dev/null
@@ -1,135 +0,0 @@
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_pkg_swig.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_PKG_SWIG([major.minor.micro], [action-if-found], [action-if-not-found])
-#
-# DESCRIPTION
-#
-# This macro searches for a SWIG installation on your system. If found,
-# then SWIG is AC_SUBST'd; if not found, then $SWIG is empty. If SWIG is
-# found, then SWIG_LIB is set to the SWIG library path, and AC_SUBST'd.
-#
-# You can use the optional first argument to check if the version of the
-# available SWIG is greater than or equal to the value of the argument. It
-# should have the format: N[.N[.N]] (N is a number between 0 and 999. Only
-# the first N is mandatory.) If the version argument is given (e.g.
-# 1.3.17), AX_PKG_SWIG checks that the swig package is this version number
-# or higher.
-#
-# As usual, action-if-found is executed if SWIG is found, otherwise
-# action-if-not-found is executed.
-#
-# In configure.in, use as:
-#
-# AX_PKG_SWIG(1.3.17, [], [ AC_MSG_ERROR([SWIG is required to build..]) ])
-# AX_SWIG_ENABLE_CXX
-# AX_SWIG_MULTI_MODULE_SUPPORT
-# AX_SWIG_PYTHON
-#
-# LICENSE
-#
-# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
-# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
-# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
-# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
-# Copyright (c) 2011 Murray Cumming <murrayc@openismus.com>
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 2 of the License, or (at your
-# option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 8
-
-AC_DEFUN([AX_PKG_SWIG],[
- # Ubuntu has swig 2.0 as /usr/bin/swig2.0
- AC_PATH_PROGS([SWIG],[swig swig2.0])
- if test -z "$SWIG" ; then
- m4_ifval([$3],[$3],[:])
- elif test -n "$1" ; then
- AC_MSG_CHECKING([SWIG version])
- [swig_version=`$SWIG -version 2>&1 | grep 'SWIG Version' | sed 's/.*\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\).*/\1/g'`]
- AC_MSG_RESULT([$swig_version])
- if test -n "$swig_version" ; then
- # Calculate the required version number components
- [required=$1]
- [required_major=`echo $required | sed 's/[^0-9].*//'`]
- if test -z "$required_major" ; then
- [required_major=0]
- fi
- [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
- [required_minor=`echo $required | sed 's/[^0-9].*//'`]
- if test -z "$required_minor" ; then
- [required_minor=0]
- fi
- [required=`echo $required | sed 's/[0-9]*[^0-9]//'`]
- [required_patch=`echo $required | sed 's/[^0-9].*//'`]
- if test -z "$required_patch" ; then
- [required_patch=0]
- fi
- # Calculate the available version number components
- [available=$swig_version]
- [available_major=`echo $available | sed 's/[^0-9].*//'`]
- if test -z "$available_major" ; then
- [available_major=0]
- fi
- [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
- [available_minor=`echo $available | sed 's/[^0-9].*//'`]
- if test -z "$available_minor" ; then
- [available_minor=0]
- fi
- [available=`echo $available | sed 's/[0-9]*[^0-9]//'`]
- [available_patch=`echo $available | sed 's/[^0-9].*//'`]
- if test -z "$available_patch" ; then
- [available_patch=0]
- fi
- # Convert the version tuple into a single number for easier comparison.
- # Using base 100 should be safe since SWIG internally uses BCD values
- # to encode its version number.
- required_swig_vernum=`expr $required_major \* 10000 \
- \+ $required_minor \* 100 \+ $required_patch`
- available_swig_vernum=`expr $available_major \* 10000 \
- \+ $available_minor \* 100 \+ $available_patch`
-
- if test $available_swig_vernum -lt $required_swig_vernum; then
- AC_MSG_WARN([SWIG version >= $1 is required. You have $swig_version.])
- SWIG=''
- m4_ifval([$3],[$3],[])
- else
- AC_MSG_CHECKING([for SWIG library])
- SWIG_LIB=`$SWIG -swiglib`
- AC_MSG_RESULT([$SWIG_LIB])
- m4_ifval([$2],[$2],[])
- fi
- else
- AC_MSG_WARN([cannot determine SWIG version])
- SWIG=''
- m4_ifval([$3],[$3],[])
- fi
- fi
- AC_SUBST([SWIG_LIB])
-])
diff --git a/m4/ax_python.m4 b/m4/ax_python.m4
deleted file mode 100644
index 1bc9d8a2..00000000
--- a/m4/ax_python.m4
+++ /dev/null
@@ -1,97 +0,0 @@
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_python.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_PYTHON
-#
-# DESCRIPTION
-#
-# This macro does a complete Python development environment check.
-#
-# It recurses through several python versions (from 2.1 to 2.6 in this
-# version), looking for an executable. When it finds an executable, it
-# looks to find the header files and library.
-#
-# It sets PYTHON_BIN to the name of the python executable,
-# PYTHON_INCLUDE_DIR to the directory holding the header files, and
-# PYTHON_LIB to the name of the Python library.
-#
-# This macro calls AC_SUBST on PYTHON_BIN (via AC_CHECK_PROG),
-# PYTHON_INCLUDE_DIR and PYTHON_LIB.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Michael Tindal
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 2 of the License, or (at your
-# option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 9
-
-AC_DEFUN([AX_PYTHON],
-[AC_MSG_CHECKING(for python build information)
-AC_MSG_RESULT([])
-for python in python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python; do
-AC_CHECK_PROGS(PYTHON_BIN, [$python])
-ax_python_bin=$PYTHON_BIN
-if test x$ax_python_bin != x; then
- AC_CHECK_LIB($ax_python_bin, main, ax_python_lib=$ax_python_bin, ax_python_lib=no)
- AC_CHECK_HEADER([$ax_python_bin/Python.h],
- [[ax_python_header=`locate $ax_python_bin/Python.h | sed -e s,/Python.h,,`]],
- ax_python_header=no)
- if test $ax_python_lib != no; then
- if test $ax_python_header != no; then
- break;
- fi
- fi
-fi
-done
-if test x$ax_python_bin = x; then
- ax_python_bin=no
-fi
-if test x$ax_python_header = x; then
- ax_python_header=no
-fi
-if test x$ax_python_lib = x; then
- ax_python_lib=no
-fi
-
-AC_MSG_RESULT([ results of the Python check:])
-AC_MSG_RESULT([ Binary: $ax_python_bin])
-AC_MSG_RESULT([ Library: $ax_python_lib])
-AC_MSG_RESULT([ Include Dir: $ax_python_header])
-
-if test x$ax_python_header != xno; then
- PYTHON_INCLUDE_DIR=$ax_python_header
- AC_SUBST(PYTHON_INCLUDE_DIR)
-fi
-if test x$ax_python_lib != xno; then
- PYTHON_LIB=$ax_python_lib
- AC_SUBST(PYTHON_LIB)
-fi
-])dnl
diff --git a/m4/ax_python_devel.m4 b/m4/ax_python_devel.m4
deleted file mode 100644
index a62b860d..00000000
--- a/m4/ax_python_devel.m4
+++ /dev/null
@@ -1,325 +0,0 @@
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_python_devel.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_PYTHON_DEVEL([version])
-#
-# DESCRIPTION
-#
-# Note: Defines as a precious variable "PYTHON_VERSION". Don't override it
-# in your configure.ac.
-#
-# This macro checks for Python and tries to get the include path to
-# 'Python.h'. It provides the $(PYTHON_CPPFLAGS) and $(PYTHON_LDFLAGS)
-# output variables. It also exports $(PYTHON_EXTRA_LIBS) and
-# $(PYTHON_EXTRA_LDFLAGS) for embedding Python in your code.
-#
-# You can search for some particular version of Python by passing a
-# parameter to this macro, for example ">= '2.3.1'", or "== '2.4'". Please
-# note that you *have* to pass also an operator along with the version to
-# match, and pay special attention to the single quotes surrounding the
-# version number. Don't use "PYTHON_VERSION" for this: that environment
-# variable is declared as precious and thus reserved for the end-user.
-#
-# This macro should work for all versions of Python >= 2.1.0. As an end
-# user, you can disable the check for the python version by setting the
-# PYTHON_NOVERSIONCHECK environment variable to something else than the
-# empty string.
-#
-# If you need to use this macro for an older Python version, please
-# contact the authors. We're always open for feedback.
-#
-# LICENSE
-#
-# Copyright (c) 2009 Sebastian Huber <sebastian-huber@web.de>
-# Copyright (c) 2009 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
-# Copyright (c) 2009 Rafael Laboissiere <rafael@laboissiere.net>
-# Copyright (c) 2009 Andrew Collier <colliera@ukzn.ac.za>
-# Copyright (c) 2009 Matteo Settenvini <matteo@member.fsf.org>
-# Copyright (c) 2009 Horst Knorr <hk_classes@knoda.org>
-#
-# This program is free software: you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation, either version 3 of the License, or (at your
-# option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 8
-
-AU_ALIAS([AC_PYTHON_DEVEL], [AX_PYTHON_DEVEL])
-AC_DEFUN([AX_PYTHON_DEVEL],[
- #
- # Allow the use of a (user set) custom python version
- #
- AC_ARG_VAR([PYTHON_VERSION],[The installed Python
- version to use, for example '2.3'. This string
- will be appended to the Python interpreter
- canonical name.])
-
- AC_PATH_PROG([PYTHON],[python[$PYTHON_VERSION]])
- if test -z "$PYTHON"; then
- AC_MSG_ERROR([Cannot find python$PYTHON_VERSION in your system path])
- PYTHON_VERSION=""
- fi
-
- #
- # Check for a version of Python >= 2.1.0
- #
- AC_MSG_CHECKING([for a version of Python >= '2.1.0'])
- ac_supports_python_ver=`$PYTHON -c "import sys; \
- ver = sys.version.split ()[[0]]; \
- print (ver >= '2.1.0')"`
- if test "$ac_supports_python_ver" != "True"; then
- if test -z "$PYTHON_NOVERSIONCHECK"; then
- AC_MSG_RESULT([no])
- AC_MSG_FAILURE([
-This version of the AC@&t@_PYTHON_DEVEL macro
-doesn't work properly with versions of Python before
-2.1.0. You may need to re-run configure, setting the
-variables PYTHON_CPPFLAGS, PYTHON_LDFLAGS, PYTHON_SITE_PKG,
-PYTHON_EXTRA_LIBS and PYTHON_EXTRA_LDFLAGS by hand.
-Moreover, to disable this check, set PYTHON_NOVERSIONCHECK
-to something else than an empty string.
-])
- else
- AC_MSG_RESULT([skip at user request])
- fi
- else
- AC_MSG_RESULT([yes])
- fi
-
- #
- # if the macro parameter ``version'' is set, honour it
- #
- if test -n "$1"; then
- AC_MSG_CHECKING([for a version of Python $1])
- ac_supports_python_ver=`$PYTHON -c "import sys; \
- ver = sys.version.split ()[[0]]; \
- print (ver $1)"`
- if test "$ac_supports_python_ver" = "True"; then
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- AC_MSG_ERROR([this package requires Python $1.
-If you have it installed, but it isn't the default Python
-interpreter in your system path, please pass the PYTHON_VERSION
-variable to configure. See ``configure --help'' for reference.
-])
- PYTHON_VERSION=""
- fi
- fi
-
- #
- # Check if you have distutils, else fail
- #
- AC_MSG_CHECKING([for the distutils Python package])
- ac_distutils_result=`$PYTHON -c "import distutils" 2>&1`
- if test -z "$ac_distutils_result"; then
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- AC_MSG_ERROR([cannot import Python module "distutils".
-Please check your Python installation. The error was:
-$ac_distutils_result])
- PYTHON_VERSION=""
- fi
-
- #
- # Check for Python include path
- #
- AC_MSG_CHECKING([for Python include path])
- if test -z "$PYTHON_CPPFLAGS"; then
- python_path=`$PYTHON -c "import distutils.sysconfig; \
- print (distutils.sysconfig.get_python_inc ());"`
- if test -n "${python_path}"; then
- python_path="-I$python_path"
- fi
- PYTHON_CPPFLAGS=$python_path
- fi
- AC_MSG_RESULT([$PYTHON_CPPFLAGS])
- AC_SUBST([PYTHON_CPPFLAGS])
-
- #
- # Check for Python library path
- #
- AC_MSG_CHECKING([for Python library path])
- if test -z "$PYTHON_LDFLAGS"; then
- # (makes two attempts to ensure we've got a version number
- # from the interpreter)
- ac_python_version=`cat<<EOD | $PYTHON -
-
-# join all versioning strings, on some systems
-# major/minor numbers could be in different list elements
-from distutils.sysconfig import *
-ret = ''
-for e in get_config_vars ('VERSION'):
- if (e != None):
- ret += e
-print (ret)
-EOD`
-
- if test -z "$ac_python_version"; then
- if test -n "$PYTHON_VERSION"; then
- ac_python_version=$PYTHON_VERSION
- else
- ac_python_version=`$PYTHON -c "import sys; \
- print (sys.version[[:3]])"`
- fi
- fi
-
- # Make the versioning information available to the compiler
- AC_DEFINE_UNQUOTED([HAVE_PYTHON], ["$ac_python_version"],
- [If available, contains the Python version number currently in use.])
-
- # First, the library directory:
- ac_python_libdir=`cat<<EOD | $PYTHON -
-
-# There should be only one
-import distutils.sysconfig
-for e in distutils.sysconfig.get_config_vars ('LIBDIR'):
- if e != None:
- print (e)
- break
-EOD`
-
- # Before checking for libpythonX.Y, we need to know
- # the extension the OS we're on uses for libraries
- # (we take the first one, if there's more than one fix me!):
- ac_python_soext=`$PYTHON -c \
- "import distutils.sysconfig; \
- print (distutils.sysconfig.get_config_vars('SO')[[0]])"`
-
- # Now, for the library:
- ac_python_soname=`$PYTHON -c \
- "import distutils.sysconfig; \
- print (distutils.sysconfig.get_config_vars('LDLIBRARY')[[0]])"`
-
- # Strip away extension from the end to canonicalize its name:
- ac_python_library=`echo "$ac_python_soname" | sed "s/${ac_python_soext}$//"`
-
- # This small piece shamelessly adapted from PostgreSQL python macro;
- # credits goes to momjian, I think. I'd like to put the right name
- # in the credits, if someone can point me in the right direction... ?
- #
- if test -n "$ac_python_libdir" -a -n "$ac_python_library" \
- -a x"$ac_python_library" != x"$ac_python_soname"
- then
- # use the official shared library
- ac_python_library=`echo "$ac_python_library" | sed "s/^lib//"`
- PYTHON_LDFLAGS="-L$ac_python_libdir -l$ac_python_library"
- else
- # old way: use libpython from python_configdir
- ac_python_libdir=`$PYTHON -c \
- "from distutils.sysconfig import get_python_lib as f; \
- import os; \
- print (os.path.join(f(plat_specific=1, standard_lib=1), 'config'));"`
- PYTHON_LDFLAGS="-L$ac_python_libdir -lpython$ac_python_version"
- fi
-
- if test -z "PYTHON_LDFLAGS"; then
- AC_MSG_ERROR([
- Cannot determine location of your Python DSO. Please check it was installed with
- dynamic libraries enabled, or try setting PYTHON_LDFLAGS by hand.
- ])
- fi
- fi
- AC_MSG_RESULT([$PYTHON_LDFLAGS])
- AC_SUBST([PYTHON_LDFLAGS])
-
- #
- # Check for site packages
- #
- AC_MSG_CHECKING([for Python site-packages path])
- if test -z "$PYTHON_SITE_PKG"; then
- PYTHON_SITE_PKG=`$PYTHON -c "import distutils.sysconfig; \
- print (distutils.sysconfig.get_python_lib(0,0));"`
- fi
- AC_MSG_RESULT([$PYTHON_SITE_PKG])
- AC_SUBST([PYTHON_SITE_PKG])
-
- #
- # libraries which must be linked in when embedding
- #
- AC_MSG_CHECKING(python extra libraries)
- if test -z "$PYTHON_EXTRA_LIBS"; then
- PYTHON_EXTRA_LIBS=`$PYTHON -c "import distutils.sysconfig; \
- conf = distutils.sysconfig.get_config_var; \
- print (conf('LOCALMODLIBS') + ' ' + conf('LIBS'))"`
- fi
- AC_MSG_RESULT([$PYTHON_EXTRA_LIBS])
- AC_SUBST(PYTHON_EXTRA_LIBS)
-
- #
- # linking flags needed when embedding
- #
- AC_MSG_CHECKING(python extra linking flags)
- if test -z "$PYTHON_EXTRA_LDFLAGS"; then
- PYTHON_EXTRA_LDFLAGS=`$PYTHON -c "import distutils.sysconfig; \
- conf = distutils.sysconfig.get_config_var; \
- print (conf('LINKFORSHARED'))"`
- fi
- AC_MSG_RESULT([$PYTHON_EXTRA_LDFLAGS])
- AC_SUBST(PYTHON_EXTRA_LDFLAGS)
-
- #
- # final check to see if everything compiles alright
- #
- AC_MSG_CHECKING([consistency of all components of python development environment])
- # save current global flags
- ac_save_LIBS="$LIBS"
- ac_save_CPPFLAGS="$CPPFLAGS"
- LIBS="$ac_save_LIBS $PYTHON_LDFLAGS $PYTHON_EXTRA_LDFLAGS $PYTHON_EXTRA_LIBS"
- CPPFLAGS="$ac_save_CPPFLAGS $PYTHON_CPPFLAGS"
- AC_LANG_PUSH([C])
- AC_LINK_IFELSE([
- AC_LANG_PROGRAM([[#include <Python.h>]],
- [[Py_Initialize();]])
- ],[pythonexists=yes],[pythonexists=no])
- AC_LANG_POP([C])
- # turn back to default flags
- CPPFLAGS="$ac_save_CPPFLAGS"
- LIBS="$ac_save_LIBS"
-
- AC_MSG_RESULT([$pythonexists])
-
- if test ! "x$pythonexists" = "xyes"; then
- AC_MSG_FAILURE([
- Could not link test program to Python. Maybe the main Python library has been
- installed in some non-standard library path. If so, pass it to configure,
- via the LDFLAGS environment variable.
- Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib"
- ============================================================================
- ERROR!
- You probably have to install the development version of the Python package
- for your distribution. The exact name of this package varies among them.
- ============================================================================
- ])
- PYTHON_VERSION=""
- fi
-
- #
- # all done!
- #
-])
diff --git a/m4/ax_swig_python.m4 b/m4/ax_swig_python.m4
deleted file mode 100644
index 8fd3df5a..00000000
--- a/m4/ax_swig_python.m4
+++ /dev/null
@@ -1,64 +0,0 @@
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_swig_python.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_SWIG_PYTHON([use-shadow-classes = {no, yes}])
-#
-# DESCRIPTION
-#
-# Checks for Python and provides the $(AX_SWIG_PYTHON_CPPFLAGS), and
-# $(AX_SWIG_PYTHON_OPT) output variables.
-#
-# $(AX_SWIG_PYTHON_OPT) contains all necessary SWIG options to generate
-# code for Python. Shadow classes are enabled unless the value of the
-# optional first argument is exactly 'no'. If you need multi module
-# support (provided by the AX_SWIG_MULTI_MODULE_SUPPORT macro) use
-# $(AX_SWIG_PYTHON_LIBS) to link against the appropriate library. It
-# contains the SWIG Python runtime library that is needed by the type
-# check system for example.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Sebastian Huber <sebastian-huber@web.de>
-# Copyright (c) 2008 Alan W. Irwin <irwin@beluga.phys.uvic.ca>
-# Copyright (c) 2008 Rafael Laboissiere <rafael@laboissiere.net>
-# Copyright (c) 2008 Andrew Collier <colliera@ukzn.ac.za>
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 2 of the License, or (at your
-# option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
-# Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception, the respective Autoconf Macro's copyright owner
-# gives unlimited permission to copy, distribute and modify the configure
-# scripts that are the output of Autoconf when processing the Macro. You
-# need not follow the terms of the GNU General Public License when using
-# or distributing such scripts, even though portions of the text of the
-# Macro appear in them. The GNU General Public License (GPL) does govern
-# all other use of the material that constitutes the Autoconf Macro.
-#
-# This special exception to the GPL applies to versions of the Autoconf
-# Macro released by the Autoconf Archive. When you make and distribute a
-# modified version of the Autoconf Macro, you may extend this special
-# exception to the GPL to apply to your modified version as well.
-
-#serial 7
-
-AU_ALIAS([SWIG_PYTHON], [AX_SWIG_PYTHON])
-AC_DEFUN([AX_SWIG_PYTHON],[
- AC_REQUIRE([AX_PKG_SWIG])
- AC_REQUIRE([AX_PYTHON_DEVEL])
- test "x$1" != "xno" || swig_shadow=" -noproxy"
- AC_SUBST([AX_SWIG_PYTHON_OPT],[-python$swig_shadow])
- AC_SUBST([AX_SWIG_PYTHON_CPPFLAGS],[$PYTHON_CPPFLAGS])
-])
diff --git a/make.log b/make.log
deleted file mode 100644
index d4379b50..00000000
--- a/make.log
+++ /dev/null
@@ -1,355 +0,0 @@
-find: `vendor': No such file or directory
-============================================
-PLATFORM_VERSION_CODENAME=REL
-PLATFORM_VERSION=7.0
-TARGET_PRODUCT=aosp_bullhead
-TARGET_BUILD_VARIANT=eng
-TARGET_BUILD_TYPE=release
-TARGET_BUILD_APPS=
-TARGET_ARCH=arm64
-TARGET_ARCH_VARIANT=armv8-a
-TARGET_CPU_VARIANT=cortex-a53
-TARGET_2ND_ARCH=arm
-TARGET_2ND_ARCH_VARIANT=armv7-a-neon
-TARGET_2ND_CPU_VARIANT=cortex-a53.a57
-HOST_ARCH=x86_64
-HOST_2ND_ARCH=x86
-HOST_OS=linux
-HOST_OS_EXTRA=Linux-3.13.0-95-generic-x86_64-with-Ubuntu-14.04-trusty
-HOST_CROSS_OS=windows
-HOST_CROSS_ARCH=x86
-HOST_CROSS_2ND_ARCH=x86_64
-HOST_BUILD_TYPE=release
-BUILD_ID=NYC
-OUT_DIR=out
-AUX_OS_VARIANT_LIST=
-============================================
-make: Entering directory `/usr/local/google/home/pstew/build/aosp'
-ninja: no work to do.
-ninja: no work to do.
-Running kati to generate build-aosp_bullhead-mmm-external_libnl_Android.mk.ninja...
-No need to regenerate ninja file
-Starting build with ninja
-ninja: Entering directory `.'
-[ 1% 1/68] target thumb C: libnl_32 <= external/libnl/lib/cache.c
-[ 2% 2/68] target thumb C: libnl_32 <= external/libnl/lib/data.c
-external/libnl/lib/data.c:119:24: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- memcpy(data->d_data + data->d_size, buf, size);
- ~~~~~~~~~~~~ ^
-external/libnl/lib/data.c:121:24: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- memset(data->d_data + data->d_size, 0, size);
- ~~~~~~~~~~~~ ^
-2 warnings generated.
-[ 4% 3/68] target thumb C: libnl_32 <= external/libnl/lib/nl.c
-external/libnl/lib/nl.c:694:18: warning: comparison of integers of different signs: '__kernel_size_t' (aka 'unsigned int') and 'ssize_t' (aka 'int') [-Wsign-compare]
- if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) {
- ~~~~~~~~~~~ ^ ~
-external/libnl/lib/nl.c:786:29: warning: missing field 'nl_pad' initializer [-Wmissing-field-initializers]
- struct sockaddr_nl nla = {0};
- ^
-external/libnl/lib/nl.c:917:23: warning: comparison of integers of different signs: '__u32' (aka 'unsigned int') and 'int' [-Wsign-compare]
- if (hdr->nlmsg_len < nlmsg_size(sizeof(*e))) {
- ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~
-3 warnings generated.
-[ 5% 4/68] target thumb C: libnl_32 <= external/libnl/lib/cache_mngr.c
-[ 7% 5/68] target thumb C: libnl_32 <= external/libnl/lib/socket.c
-[ 8% 6/68] target thumb C: libnl_32 <= external/libnl/lib/addr.c
-external/libnl/lib/addr.c:707:14: warning: comparison of integers of different signs: 'socklen_t' (aka 'int') and 'unsigned int' [-Wsign-compare]
- if (*salen < sizeof(*sai))
- ~~~~~~ ^ ~~~~~~~~~~~~
-external/libnl/lib/addr.c:719:14: warning: comparison of integers of different signs: 'socklen_t' (aka 'int') and 'unsigned int' [-Wsign-compare]
- if (*salen < sizeof(*sa6))
- ~~~~~~ ^ ~~~~~~~~~~~~
-external/libnl/lib/addr.c:990:24: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
- if (addr->a_prefixlen != (8 * addr->a_len)) {
- ~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
-3 warnings generated.
-[ 10% 7/68] target thumb C: libnl_32 <= external/libnl/lib/fib_lookup/lookup.c
-external/libnl/lib/fib_lookup/lookup.c:215:30: warning: missing field 'fl_fwmark' initializer [-Wmissing-field-initializers]
- struct fib_result_nl fr = {0};
- ^
-1 warning generated.
-[ 11% 8/68] target thumb C: libnl_32 <= external/libnl/lib/fib_lookup/request.c
-[ 13% 9/68] target thumb C: libnl_32 <= external/libnl/lib/object.c
-external/libnl/lib/object.c:134:22: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- memcpy((void *)new + doff, (void *)obj + doff, size);
- ~~~~~~~~~~~ ^
-external/libnl/lib/object.c:134:42: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- memcpy((void *)new + doff, (void *)obj + doff, size);
- ~~~~~~~~~~~ ^
-2 warnings generated.
-[ 14% 10/68] target thumb C: libnl_32 <= external/libnl/lib/msg.c
-external/libnl/lib/msg.c:168:21: warning: comparison of integers of different signs: 'const __u32' (aka 'const unsigned int') and 'int' [-Wsign-compare]
- if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
- ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~
-external/libnl/lib/msg.c:183:18: warning: comparison of integers of different signs: 'const __u32' (aka 'const unsigned int') and 'int' [-Wsign-compare]
- nlh->nlmsg_len <= remaining);
- ~~~~~~~~~~~~~~ ^ ~~~~~~~~~
-external/libnl/lib/msg.c:367:10: warning: comparison of integers of different signs: 'size_t' (aka 'unsigned int') and 'int' [-Wsign-compare]
- if (max < nlmsg_total_size(0))
- ~~~ ^ ~~~~~~~~~~~~~~~~~~~
-external/libnl/lib/msg.c:418:6: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- buf += nlmsg_len;
- ~~~ ^
-external/libnl/lib/msg.c:422:14: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- memset(buf + len, 0, tlen - len);
- ~~~ ^
-external/libnl/lib/msg.c:842:7: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- data += GENL_HDRLEN;
- ~~~~ ^
-external/libnl/lib/msg.c:855:9: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- data += hdrsize;
- ~~~~ ^
-external/libnl/lib/msg.c:836:18: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
- if (*payloadlen < GENL_HDRLEN)
- ~~~~~~~~~~~ ^ ~~~~~~~~~~~
-external/libnl/lib/msg.c:897:32: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- dump_hex(ofd, nla_data(nla) + alen,
- ~~~~~~~~~~~~~ ^
-external/libnl/lib/msg.c:920:4: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
- strerror_r(-err->error, buf, sizeof(buf)));
- ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-external/libnl/lib/msg.c:915:21: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
- if (nlmsg_len(hdr) >= sizeof(*err)) {
- ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
-11 warnings generated.
-[ 16% 11/68] target thumb C: libnl_32 <= external/libnl/lib/attr.c
-external/libnl/lib/attr.c:150:19: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
- return remaining >= sizeof(*nla) &&
- ~~~~~~~~~ ^ ~~~~~~~~~~~~
-external/libnl/lib/attr.c:208:19: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
- if (nla_len(nla) < minlen)
- ~~~~~~~~~~~~ ^ ~~~~~~
-external/libnl/lib/attr.c:463:11: warning: comparison of integers of different signs: 'int' and 'size_t' (aka 'unsigned int') [-Wsign-compare]
- if (tlen > msg->nm_size)
- ~~~~ ^ ~~~~~~~~~~~~
-external/libnl/lib/attr.c:653:26: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
- if (nla && nla_len(nla) >= sizeof(tmp))
- ~~~~~~~~~~~~ ^ ~~~~~~~~~~~
-external/libnl/lib/attr.c:815:41: warning: arithmetic on pointers to void is a GNU extension [-Wpointer-arith]
- len = (void *) nlmsg_tail(msg->nm_nlh) - (void *) start;
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~
-external/libnl/lib/attr.c:863:41: warning: arithmetic on pointers to void is a GNU extension [-Wpointer-arith]
- len = (void *) nlmsg_tail(msg->nm_nlh) - (void *) attr;
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~
-6 warnings generated.
-[ 17% 12/68] target thumb C: libnl_32 <= external/libnl/lib/utils.c
-[ 19% 13/68] target thumb C: libnl_32 <= external/libnl/lib/handlers.c
-external/libnl/lib/handlers.c:85:3: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
- strerror_r(-e->error, buf, sizeof(buf)));
- ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-external/libnl/lib/handlers.c:206:11: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
- if (kind < 0 || kind > NL_CB_KIND_MAX)
- ~~~~ ^ ~
-external/libnl/lib/handlers.c:296:11: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
- if (type < 0 || type > NL_CB_TYPE_MAX)
- ~~~~ ^ ~
-external/libnl/lib/handlers.c:299:11: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
- if (kind < 0 || kind > NL_CB_KIND_MAX)
- ~~~~ ^ ~
-external/libnl/lib/handlers.c:346:11: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
- if (kind < 0 || kind > NL_CB_KIND_MAX)
- ~~~~ ^ ~
-5 warnings generated.
-[ 20% 14/68] target thumb C: libnl_32 <= external/libnl/lib/cache_mngt.c
-[ 22% 15/68] target thumb C: libnl_32 <= external/libnl/lib/genl/mngt.c
-external/libnl/lib/genl/mngt.c:250:22: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
- if (ops->co_hdrsize < GENL_HDRSIZE(0)) {
- ~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
-1 warning generated.
-[ 23% 16/68] target thumb C: libnl_32 <= external/libnl/lib/genl/ctrl.c
-[ 25% 17/68] target thumb C: libnl_32 <= external/libnl/lib/genl/genl.c
-external/libnl/lib/genl/genl.c:125:24: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
- if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen))
- ~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~
-external/libnl/lib/genl/genl.c:261:32: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- return genlmsg_user_hdr(gnlh) + NLMSG_ALIGN(hdrlen);
- ~~~~~~~~~~~~~~~~~~~~~~ ^
-external/libnl/lib/genl/genl.c:365:25: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- return nlmsg_data(nlh) + GENL_HDRLEN;
- ~~~~~~~~~~~~~~~ ^
-3 warnings generated.
-[ 26% 18/68] target thumb C: libnl_32 <= external/libnl/lib/genl/family.c
-[ 27% 19/68] target thumb C: libnl_32 <= external/libnl/lib/route/rtnl.c
-[ 29% 20/68] target thumb C: libnl_32 <= external/libnl/lib/route/route_utils.c
-[ 30% 21/68] target thumb C: libnl_32 <= external/libnl/lib/error.c
-[ 32% 22/68] target thumb C: libnl_32 <= external/libnl/lib/netfilter/nfnl.c
-[ 33% 23/68] target thumb C: libnl_32 <= external/libnl/lib/version.c
-[ 35% 24/68] target thumb C: libnl_32 <= external/libnl/lib/hash.c
-[ 36% 25/68] target thumb C: libnl_32 <= external/libnl/lib/hashtable.c
-external/libnl/lib/hashtable.c:194:9: warning: invalid application of 'sizeof' to a void type [-Wpointer-arith]
- return(__nl_hash(k, length, initval));
- ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-external/libnl/include/netlink/hash.h:64:62: note: expanded from macro '__nl_hash'
-#define __nl_hash(p, num, base) nl_hash_any((p), (num)*sizeof(*(p)), (base))
- ^~~~~~
-1 warning generated.
-[ 38% 26/68] target StaticLib: libnl_32 (out/target/product/bullhead/obj_arm/STATIC_LIBRARIES/libnl_intermediates/libnl.a)
-[ 39% 27/68] target SharedLib: libnl_32 (out/target/product/bullhead/obj_arm/SHARED_LIBRARIES/libnl_intermediates/LINKED/libnl.so)
-[ 41% 28/68] target Pack Relocations: libnl_32 (out/target/product/bullhead/obj_arm/SHARED_LIBRARIES/libnl_intermediates/PACKED/libnl.so)
-[ 42% 29/68] target Symbolic: libnl_32 (out/target/product/bullhead/symbols/system/lib/libnl.so)
-[ 44% 30/68] target Strip (mini debug info): libnl_32 (out/target/product/bullhead/obj_arm/lib/libnl.so)
-[ 45% 31/68] Notice file: external/libnl/NOTICE -- out/target/product/bullhead/obj/NOTICE_FILES/src//system/lib/libnl.so.txt
-[ 47% 32/68] Notice file: external/libnl/NOTICE -- out/target/product/bullhead/obj/NOTICE_FILES/src//system/lib64/libnl.a.txt
-[ 48% 33/68] Notice file: external/libnl/NOTICE -- out/target/product/bullhead/obj/NOTICE_FILES/src//system/lib/libnl.a.txt
-[ 50% 34/68] Install: out/target/product/bullhead/system/lib/libnl.so
-[ 51% 35/68] target C: libnl <= external/libnl/lib/cache.c
-[ 52% 36/68] target C: libnl <= external/libnl/lib/data.c
-external/libnl/lib/data.c:119:24: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- memcpy(data->d_data + data->d_size, buf, size);
- ~~~~~~~~~~~~ ^
-external/libnl/lib/data.c:121:24: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- memset(data->d_data + data->d_size, 0, size);
- ~~~~~~~~~~~~ ^
-2 warnings generated.
-[ 54% 37/68] target C: libnl <= external/libnl/lib/nl.c
-external/libnl/lib/nl.c:694:18: warning: comparison of integers of different signs: '__kernel_size_t' (aka 'unsigned long') and 'ssize_t' (aka 'long') [-Wsign-compare]
- if (iov.iov_len < n || (msg.msg_flags & MSG_TRUNC)) {
- ~~~~~~~~~~~ ^ ~
-external/libnl/lib/nl.c:786:29: warning: missing field 'nl_pad' initializer [-Wmissing-field-initializers]
- struct sockaddr_nl nla = {0};
- ^
-external/libnl/lib/nl.c:917:23: warning: comparison of integers of different signs: '__u32' (aka 'unsigned int') and 'int' [-Wsign-compare]
- if (hdr->nlmsg_len < nlmsg_size(sizeof(*e))) {
- ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~
-3 warnings generated.
-[ 55% 38/68] target C: libnl <= external/libnl/lib/addr.c
-external/libnl/lib/addr.c:990:24: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
- if (addr->a_prefixlen != (8 * addr->a_len)) {
- ~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
-1 warning generated.
-[ 57% 39/68] target C: libnl <= external/libnl/lib/cache_mngr.c
-[ 58% 40/68] target C: libnl <= external/libnl/lib/socket.c
-[ 60% 41/68] target C: libnl <= external/libnl/lib/fib_lookup/lookup.c
-external/libnl/lib/fib_lookup/lookup.c:215:30: warning: missing field 'fl_fwmark' initializer [-Wmissing-field-initializers]
- struct fib_result_nl fr = {0};
- ^
-1 warning generated.
-[ 61% 42/68] target C: libnl <= external/libnl/lib/msg.c
-external/libnl/lib/msg.c:168:21: warning: comparison of integers of different signs: 'const __u32' (aka 'const unsigned int') and 'int' [-Wsign-compare]
- if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen))
- ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~~~~
-external/libnl/lib/msg.c:183:18: warning: comparison of integers of different signs: 'const __u32' (aka 'const unsigned int') and 'int' [-Wsign-compare]
- nlh->nlmsg_len <= remaining);
- ~~~~~~~~~~~~~~ ^ ~~~~~~~~~
-external/libnl/lib/msg.c:367:10: warning: comparison of integers of different signs: 'size_t' (aka 'unsigned long') and 'int' [-Wsign-compare]
- if (max < nlmsg_total_size(0))
- ~~~ ^ ~~~~~~~~~~~~~~~~~~~
-external/libnl/lib/msg.c:418:6: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- buf += nlmsg_len;
- ~~~ ^
-external/libnl/lib/msg.c:422:14: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- memset(buf + len, 0, tlen - len);
- ~~~ ^
-external/libnl/lib/msg.c:842:7: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- data += GENL_HDRLEN;
- ~~~~ ^
-external/libnl/lib/msg.c:855:9: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- data += hdrsize;
- ~~~~ ^
-external/libnl/lib/msg.c:836:18: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
- if (*payloadlen < GENL_HDRLEN)
- ~~~~~~~~~~~ ^ ~~~~~~~~~~~
-external/libnl/lib/msg.c:897:32: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- dump_hex(ofd, nla_data(nla) + alen,
- ~~~~~~~~~~~~~ ^
-external/libnl/lib/msg.c:920:4: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
- strerror_r(-err->error, buf, sizeof(buf)));
- ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-external/libnl/lib/msg.c:915:21: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
- if (nlmsg_len(hdr) >= sizeof(*err)) {
- ~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~
-11 warnings generated.
-[ 63% 43/68] target C: libnl <= external/libnl/lib/fib_lookup/request.c
-[ 64% 44/68] target C: libnl <= external/libnl/lib/attr.c
-external/libnl/lib/attr.c:150:19: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
- return remaining >= sizeof(*nla) &&
- ~~~~~~~~~ ^ ~~~~~~~~~~~~
-external/libnl/lib/attr.c:208:19: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
- if (nla_len(nla) < minlen)
- ~~~~~~~~~~~~ ^ ~~~~~~
-external/libnl/lib/attr.c:463:11: warning: comparison of integers of different signs: 'int' and 'size_t' (aka 'unsigned long') [-Wsign-compare]
- if (tlen > msg->nm_size)
- ~~~~ ^ ~~~~~~~~~~~~
-external/libnl/lib/attr.c:653:26: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
- if (nla && nla_len(nla) >= sizeof(tmp))
- ~~~~~~~~~~~~ ^ ~~~~~~~~~~~
-external/libnl/lib/attr.c:815:41: warning: arithmetic on pointers to void is a GNU extension [-Wpointer-arith]
- len = (void *) nlmsg_tail(msg->nm_nlh) - (void *) start;
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~
-external/libnl/lib/attr.c:863:41: warning: arithmetic on pointers to void is a GNU extension [-Wpointer-arith]
- len = (void *) nlmsg_tail(msg->nm_nlh) - (void *) attr;
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~
-6 warnings generated.
-[ 66% 45/68] target C: libnl <= external/libnl/lib/object.c
-external/libnl/lib/object.c:134:22: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- memcpy((void *)new + doff, (void *)obj + doff, size);
- ~~~~~~~~~~~ ^
-external/libnl/lib/object.c:134:42: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- memcpy((void *)new + doff, (void *)obj + doff, size);
- ~~~~~~~~~~~ ^
-2 warnings generated.
-[ 67% 46/68] target C: libnl <= external/libnl/lib/utils.c
-[ 69% 47/68] target C: libnl <= external/libnl/lib/cache_mngt.c
-[ 70% 48/68] target C: libnl <= external/libnl/lib/handlers.c
-external/libnl/lib/handlers.c:85:3: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
- strerror_r(-e->error, buf, sizeof(buf)));
- ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-external/libnl/lib/handlers.c:206:11: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
- if (kind < 0 || kind > NL_CB_KIND_MAX)
- ~~~~ ^ ~
-external/libnl/lib/handlers.c:296:11: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
- if (type < 0 || type > NL_CB_TYPE_MAX)
- ~~~~ ^ ~
-external/libnl/lib/handlers.c:299:11: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
- if (kind < 0 || kind > NL_CB_KIND_MAX)
- ~~~~ ^ ~
-external/libnl/lib/handlers.c:346:11: warning: comparison of unsigned enum expression < 0 is always false [-Wtautological-compare]
- if (kind < 0 || kind > NL_CB_KIND_MAX)
- ~~~~ ^ ~
-5 warnings generated.
-[ 72% 49/68] target C: libnl <= external/libnl/lib/genl/ctrl.c
-[ 73% 50/68] target C: libnl <= external/libnl/lib/genl/mngt.c
-external/libnl/lib/genl/mngt.c:250:22: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
- if (ops->co_hdrsize < GENL_HDRSIZE(0)) {
- ~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~
-1 warning generated.
-[ 75% 51/68] target C: libnl <= external/libnl/lib/genl/family.c
-[ 76% 52/68] target C: libnl <= external/libnl/lib/genl/genl.c
-external/libnl/lib/genl/genl.c:125:24: warning: comparison of integers of different signs: 'int' and 'unsigned int' [-Wsign-compare]
- if (genlmsg_len(ghdr) < NLMSG_ALIGN(hdrlen))
- ~~~~~~~~~~~~~~~~~ ^ ~~~~~~~~~~~~~~~~~~~
-external/libnl/lib/genl/genl.c:261:32: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- return genlmsg_user_hdr(gnlh) + NLMSG_ALIGN(hdrlen);
- ~~~~~~~~~~~~~~~~~~~~~~ ^
-external/libnl/lib/genl/genl.c:365:25: warning: arithmetic on a pointer to void is a GNU extension [-Wpointer-arith]
- return nlmsg_data(nlh) + GENL_HDRLEN;
- ~~~~~~~~~~~~~~~ ^
-3 warnings generated.
-[ 77% 53/68] target C: libnl <= external/libnl/lib/route/rtnl.c
-[ 79% 54/68] target C: libnl <= external/libnl/lib/netfilter/nfnl.c
-[ 80% 55/68] target C: libnl <= external/libnl/lib/route/route_utils.c
-[ 82% 56/68] target C: libnl <= external/libnl/lib/error.c
-[ 83% 57/68] target C: libnl <= external/libnl/lib/hash.c
-[ 85% 58/68] target C: libnl <= external/libnl/lib/version.c
-[ 86% 59/68] target C: libnl <= external/libnl/lib/hashtable.c
-external/libnl/lib/hashtable.c:194:9: warning: invalid application of 'sizeof' to a void type [-Wpointer-arith]
- return(__nl_hash(k, length, initval));
- ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-external/libnl/include/netlink/hash.h:64:62: note: expanded from macro '__nl_hash'
-#define __nl_hash(p, num, base) nl_hash_any((p), (num)*sizeof(*(p)), (base))
- ^~~~~~
-1 warning generated.
-[ 88% 60/68] target StaticLib: libnl (out/target/product/bullhead/obj/STATIC_LIBRARIES/libnl_intermediates/libnl.a)
-[ 89% 61/68] target SharedLib: libnl (out/target/product/bullhead/obj/SHARED_LIBRARIES/libnl_intermediates/LINKED/libnl.so)
-[ 91% 62/68] target Pack Relocations: libnl (out/target/product/bullhead/obj/SHARED_LIBRARIES/libnl_intermediates/PACKED/libnl.so)
-[ 92% 63/68] target Symbolic: libnl (out/target/product/bullhead/symbols/system/lib64/libnl.so)
-[ 94% 64/68] target Strip (mini debug info): libnl (out/target/product/bullhead/obj/lib/libnl.so)
-[ 95% 65/68] Notice file: external/libnl/NOTICE -- out/target/product/bullhead/obj/NOTICE_FILES/src//system/lib64/libnl.so.txt
-[ 97% 66/68] Install: out/target/product/bullhead/system/lib64/libnl.so
-[ 98% 67/68] build out/target/product/bullhead/obj_arm/lib/libnl.so.toc
-[100% 68/68] build out/target/product/bullhead/obj/lib/libnl.so.toc
-make: Leaving directory `/usr/local/google/home/pstew/build/aosp'
-
-#### make completed successfully (13 seconds) ####
-
diff --git a/man/Makefile.am b/man/Makefile.am
deleted file mode 100644
index af1277b0..00000000
--- a/man/Makefile.am
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- Makefile -*-
-
-dist_man8_MANS = \
- nl-classid-lookup.8 \
- nl-pktloc-lookup.8 \
- nl-qdisc-add.8 nl-qdisc-delete.8 nl-qdisc-list.8 \
- genl-ctrl-list.8
diff --git a/python/Makefile.am b/python/Makefile.am
deleted file mode 100644
index a1a3426e..00000000
--- a/python/Makefile.am
+++ /dev/null
@@ -1,3 +0,0 @@
-# -*- Makefile -*-
-
-SUBDIRS = doc examples netlink tests
diff --git a/python/doc/Makefile.am b/python/doc/Makefile.am
deleted file mode 100644
index a2fe6f2b..00000000
--- a/python/doc/Makefile.am
+++ /dev/null
@@ -1,8 +0,0 @@
-# -*- Makefile -*-
-
-EXTRA_DIST = \
- conf.py \
- core.rst \
- index.rst \
- route_addr.rst \
- route.rst
diff --git a/python/examples/Makefile.am b/python/examples/Makefile.am
deleted file mode 100644
index 1cea5e2d..00000000
--- a/python/examples/Makefile.am
+++ /dev/null
@@ -1,6 +0,0 @@
-# -*- Makefile -*-
-
-EXTRA_DIST = \
- iface.py \
- nl80211.py \
- wiphy.py
diff --git a/python/netlink/Makefile.am b/python/netlink/Makefile.am
deleted file mode 100644
index 1f6eaf8f..00000000
--- a/python/netlink/Makefile.am
+++ /dev/null
@@ -1,11 +0,0 @@
-# -*- Makefile -*-
-
-SUBDIRS = route genl
-
-EXTRA_DIST = \
- capi.i \
- fixes.h \
- __init__.py \
- core.py \
- util.py \
- utils.h
diff --git a/python/netlink/capi.i b/python/netlink/capi.i
index e5d8a536..98f4e33e 100644
--- a/python/netlink/capi.i
+++ b/python/netlink/capi.i
@@ -9,13 +9,15 @@
#include <netlink/attr.h>
#include <net/if.h>
-#define DEBUG
+/* enable define below to get swig api debug messages */
+/*#define DEBUG*/
#include "utils.h"
%}
%include <stdint.i>
%include <cstring.i>
%include <cpointer.i>
+%include <exception.i>
%inline %{
struct nl_dump_params *alloc_dump_params(void)
@@ -186,6 +188,9 @@ extern void nl_socket_set_peer_groups(struct nl_sock *sk, uint32_t groups);
extern int nl_socket_set_buffer_size(struct nl_sock *, int, int);
extern void nl_socket_set_cb(struct nl_sock *, struct nl_cb *);
+extern int nl_socket_add_membership(struct nl_sock *, int);
+extern int nl_socket_drop_membership(struct nl_sock *, int);
+
extern int nl_send_auto_complete(struct nl_sock *, struct nl_msg *);
extern int nl_recvmsgs(struct nl_sock *, struct nl_cb *);
@@ -808,6 +813,19 @@ extern void *nla_data(struct nlattr *);
%typemap(out) void *;
extern int nla_type(const struct nlattr *);
+%typemap(in) (int, const void *) {
+ $1 = Py_SIZE($input);
+ if (PyByteArray_Check($input)) {
+ $2 = ($2_ltype)PyByteArray_AsString($input);
+ } else if (PyString_Check($input)) {
+ $2 = ($2_ltype)PyString_AsString($input);
+ } else
+ SWIG_exception(SWIG_TypeError,
+ "pointer must be bytearray or string.");
+}
+extern int nla_put(struct nl_msg *, int, int, const void *);
+%typemap(in) const void *;
+
/* Integer attribute */
extern uint8_t nla_get_u8(struct nlattr *);
extern int nla_put_u8(struct nl_msg *, int, uint8_t);
diff --git a/python/netlink/genl/Makefile.am b/python/netlink/genl/Makefile.am
deleted file mode 100644
index 9e309047..00000000
--- a/python/netlink/genl/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-# -*- Makefile -*-
-
-EXTRA_DIST = \
- capi.i \
- __init__.py
diff --git a/python/netlink/genl/capi.i b/python/netlink/genl/capi.i
index 069e617e..fbf448fd 100644
--- a/python/netlink/genl/capi.i
+++ b/python/netlink/genl/capi.i
@@ -36,8 +36,16 @@ extern void genl_family_set_maxattr(struct genl_family *, uint32_t);
extern int genl_family_add_op(struct genl_family *, int, int);
extern int genl_family_add_grp(struct genl_family *, uint32_t , const char *);
+/* #include <linux/genetlink.h> */
+struct genlmsghdr {
+ uint8_t cmd;
+ uint8_t version;
+ uint16_t reserved;
+};
+
/* #include <netlink/genl/genl.h> */
extern int genl_connect(struct nl_sock *);
+extern struct genlmsghdr *genlmsg_hdr(struct nlmsghdr *);
extern void *genlmsg_put(struct nl_msg *, uint32_t, uint32_t,
int, int, int, uint8_t, uint8_t);
diff --git a/python/netlink/route/Makefile.am b/python/netlink/route/Makefile.am
deleted file mode 100644
index ef714f45..00000000
--- a/python/netlink/route/Makefile.am
+++ /dev/null
@@ -1,14 +0,0 @@
-# -*- Makefile -*-
-
-EXTRA_DIST = \
- capi.i \
- __init__.py \
- address.py \
- link.py \
- tc.py \
- links/__init__.py \
- links/dummy.py \
- links/inet.py \
- links/vlan.py \
- qdisc/__init__.py \
- qdisc/htb.py
diff --git a/python/netlink/utils.h b/python/netlink/utils.h
index 7836c307..3ec2fb54 100644
--- a/python/netlink/utils.h
+++ b/python/netlink/utils.h
@@ -30,7 +30,7 @@ static inline void list_del(struct list_head *entry, struct list_head *prev)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ const __typeof__( ((type *)0)->member ) *__mptr = (ptr);\
(type *)( (char *)__mptr - offsetof(type,member) );})
#ifdef DEBUG
diff --git a/python/setup.py.in b/python/setup.py.in
index 346c770f..0cd35d09 100644
--- a/python/setup.py.in
+++ b/python/setup.py.in
@@ -35,6 +35,10 @@ setup(name = 'netlink',
description = 'Python wrapper for netlink protocols',
author = 'Thomas Graf',
author_email = 'tgraf@suug.ch',
+ url = 'http://www.infradead.org/~tgr/libnl/',
+ license = 'LGPL 2',
+ platforms = 'linux2',
+ long_description = 'Experimental python bindings for libnl',
ext_modules = [netlink_capi, route_capi, genl_capi],
package_dir = {'': '@srcdir@'},
packages = ['netlink', 'netlink.genl', 'netlink.route',
diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am
deleted file mode 100644
index 15f77fa4..00000000
--- a/python/tests/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-
-# -*- Makefile -*-
-
-EXTRA_DIST = \
- test-create-bridge.py
diff --git a/src/.gitignore b/src/.gitignore
index 5de9f293..e53eb3d1 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,18 +1,30 @@
genl-ctrl-list
-/nf-ct-add
+idiag-socket-details
+nf-ct-add
+nf-ct-events
nf-ct-list
-nf-exp-list
nf-exp-add
nf-exp-delete
+nf-exp-list
nf-log
nf-monitor
+nf-queue
nl-addr-add
nl-addr-delete
nl-addr-list
+nl-class-add
+nl-class-delete
+nl-class-list
+nl-classid-lookup
+nl-cls-add
+nl-cls-delete
+nl-cls-list
nl-fib-lookup
-nl-link-list
+nl-link-enslave
nl-link-ifindex2name
+nl-link-list
nl-link-name2ifindex
+nl-link-release
nl-link-set
nl-link-stats
nl-list-caches
@@ -22,25 +34,14 @@ nl-neigh-add
nl-neigh-delete
nl-neigh-list
nl-neightbl-list
+nl-pktloc-lookup
nl-qdisc-add
nl-qdisc-delete
nl-qdisc-list
-nl-class-add
-nl-class-delete
-nl-class-list
-nl-cls-add
-nl-cls-delete
-nl-cls-list
nl-route-add
nl-route-delete
-nl-route-list
nl-route-get
+nl-route-list
nl-rule-list
nl-tctree-list
nl-util-addr
-nf-queue
-nl-classid-lookup
-nl-pktloc-lookup
-nl-link-enslave
-nl-link-release
-idiag-socket-details
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index b40b8a06..00000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,106 +0,0 @@
-# -*- Makefile -*-
-
-SUBDIRS = lib
-
-AM_CPPFLAGS = -I${top_srcdir}/include/linux-private -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DSYSCONFDIR=\"$(sysconfdir)/libnl\"
-AM_CFLAGS = -Wall
-
-LDADD = \
- ${top_builddir}/src/lib/libnl-cli-3.la \
- ${top_builddir}/lib/libnl-3.la \
- ${top_builddir}/lib/libnl-nf-3.la \
- ${top_builddir}/lib/libnl-genl-3.la \
- ${top_builddir}/lib/libnl-route-3.la \
- ${top_builddir}/lib/libnl-idiag-3.la
-
-sbin_PROGRAMS = \
- genl-ctrl-list \
- nl-qdisc-add nl-qdisc-list nl-qdisc-delete \
- nl-class-add nl-class-list nl-class-delete \
- nl-cls-add nl-cls-list nl-cls-delete \
- nl-classid-lookup \
- nl-pktloc-lookup \
- nl-link-list
-
-noinst_PROGRAMS = \
- nf-ct-list nf-ct-add nf-log nf-queue nf-monitor \
- nf-exp-list nf-exp-add nf-exp-delete \
- nl-addr-add nl-addr-delete nl-addr-list \
- nl-link-set nl-link-stats \
- nl-link-ifindex2name nl-link-name2ifindex \
- nl-neigh-add nl-neigh-delete nl-neigh-list \
- nl-rule-list \
- nl-neightbl-list \
- nl-monitor \
- nl-tctree-list \
- nl-route-add nl-route-delete nl-route-get nl-route-list \
- nl-fib-lookup \
- nl-list-caches nl-list-sockets \
- nl-util-addr \
- nl-link-enslave \
- nl-link-release \
- idiag-socket-details
-
-genl_ctrl_list_SOURCES = genl-ctrl-list.c
-
-nf_ct_list_SOURCES = nf-ct-list.c
-nf_ct_add_SOURCES = nf-ct-add.c
-nf_log_SOURCES = nf-log.c
-nf_queue_SOURCES = nf-queue.c
-nf_monitor_SOURCES = nf-monitor.c
-
-nf_exp_list_SOURCES = nf-exp-list.c
-nf_exp_add_SOURCES = nf-exp-add.c
-nf_exp_delete_SOURCES = nf-exp-delete.c
-
-nl_addr_add_SOURCES = nl-addr-add.c
-nl_addr_delete_SOURCES = nl-addr-delete.c
-nl_addr_list_SOURCES = nl-addr-list.c
-
-nl_link_list_SOURCES = nl-link-list.c
-nl_link_set_SOURCES = nl-link-set.c
-nl_link_stats_SOURCES = nl-link-stats.c
-nl_link_ifindex2name_SOURCES = nl-link-ifindex2name.c
-nl_link_name2ifindex_SOURCES = nl-link-name2ifindex.c
-
-nl_monitor_SOURCES = nl-monitor.c
-
-nl_neigh_add_SOURCES = nl-neigh-add.c
-nl_neigh_delete_SOURCES = nl-neigh-delete.c
-nl_neigh_list_SOURCES = nl-neigh-list.c
-
-nl_neightbl_list_SOURCES = nl-neightbl-list.c
-
-nl_qdisc_add_SOURCES = nl-qdisc-add.c
-nl_qdisc_delete_SOURCES = nl-qdisc-delete.c
-nl_qdisc_list_SOURCES = nl-qdisc-list.c
-
-nl_class_add_SOURCES = nl-class-add.c
-nl_class_delete_SOURCES = nl-class-delete.c
-nl_class_list_SOURCES = nl-class-list.c
-
-nl_cls_add_SOURCES = nl-cls-add.c
-nl_cls_list_SOURCES = nl-cls-list.c
-nl_cls_delete_SOURCES = nl-cls-delete.c
-
-nl_route_add_SOURCES = nl-route-add.c
-nl_route_delete_SOURCES = nl-route-delete.c
-nl_route_get_SOURCES = nl-route-get.c
-nl_route_list_SOURCES = nl-route-list.c
-
-nl_rule_list_SOURCES = nl-rule-list.c
-
-nl_tctree_list_SOURCES = nl-tctree-list.c
-
-nl_fib_lookup_SOURCES = nl-fib-lookup.c
-
-nl_list_caches_SOURCES = nl-list-caches.c
-nl_list_sockets_SOURCES = nl-list-sockets.c
-
-nl_util_addr_SOURCES = nl-util-addr.c
-
-nl_pktloc_lookup_SOURCES = nl-pktloc-lookup.c
-
-nl_classid_lookup_SOURCES = nl-classid-lookup.c
-
-idiag_socket_details_SOURCES = idiag-socket-details.c
diff --git a/src/genl-ctrl-list.c b/src/genl-ctrl-list.c
index 0895bcce..d3279a83 100644
--- a/src/genl-ctrl-list.c
+++ b/src/genl-ctrl-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/genl-ctrl-list.c List Generic Netlink Families
*
@@ -11,10 +12,12 @@
#include <netlink/cli/utils.h>
+#include <linux/genetlink.h>
+
static struct nl_cache *alloc_genl_family_cache(struct nl_sock *sk)
{
return nl_cli_alloc_cache(sk, "generic netlink family",
- genl_ctrl_alloc_cache);
+ genl_ctrl_alloc_cache);
}
static void print_usage(void)
@@ -38,11 +41,11 @@ int main(int argc, char *argv[])
.dp_type = NL_DUMP_LINE,
.dp_fd = stdout,
};
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_GENERIC);
family_cache = alloc_genl_family_cache(sock);
-
+
for (;;) {
int c, optidx = 0;
static struct option long_opts[] = {
@@ -52,7 +55,7 @@ int main(int argc, char *argv[])
{ "version", 0, 0, 'v' },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "df:hv", long_opts, &optidx);
if (c == -1)
break;
@@ -63,7 +66,7 @@ int main(int argc, char *argv[])
case 'h': print_usage(); break;
case 'v': nl_cli_print_version(); break;
}
- }
+ }
nl_cache_dump(family_cache, &params);
diff --git a/src/idiag-socket-details.c b/src/idiag-socket-details.c
index 95686768..2d7dd4bd 100644
--- a/src/idiag-socket-details.c
+++ b/src/idiag-socket-details.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/idiag-socket-details.c List socket details
*
@@ -72,7 +73,7 @@ int main(int argc, char *argv[])
}
}
- if ((err = idiagnl_msg_alloc_cache(sock, AF_INET, IDIAG_SS_ALL,
+ if ((err = idiagnl_msg_alloc_cache(sock, AF_INET, IDIAGNL_SS_ALL,
&idiag_cache))) {
nl_cli_fatal(err, "Unable to allocate idiag msg cache: %s",
nl_geterror(err));
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
deleted file mode 100644
index 2c259be6..00000000
--- a/src/lib/Makefile.am
+++ /dev/null
@@ -1,45 +0,0 @@
-# -*- Makefile -*-
-
-AM_CPPFLAGS = -I${top_srcdir}/include/linux-private -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DPKGLIBDIR=\"$(pkglibdir)\" -DSYSCONFDIR=\"$(sysconfdir)\" -rdynamic
-AM_CFLAGS = -Wall
-AM_LDFLAGS = \
- -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
-NL_LIBADD = \
- -L${top_builddir}/lib \
- -ldl
-
-#nobase_pkglib_LTLIBRARIES = cls/basic.la cls/ematch/cmp.la
-#cls_basic_la_LDFLAGS = -module -version-info 2:0:0
-#cls_ematch_cmp_la_LDFLAGS = -module -version-info 2:0:0
-
-#cls/ematch_grammar.c: cls/ematch_grammar.l
-# $(LEX) --header-file=cls/ematch_grammar.h $(LFLAGS) -o $@ $^
-
-#cls/ematch_syntax.c: cls/ematch_syntax.y
-# $(YACC) -d $(YFLAGS) -o $@ $^
-
-#cls/pktloc_grammar.c: cls/pktloc_grammar.l
-# $(LEX) --header-file=cls/pktloc_grammar.h $(LFLAGS) -o $@ $^
-
-#cls/pktloc_syntax.c: cls/pktloc_syntax.y
-# $(YACC) -d $(YFLAGS) -o $@ $^
-
-#CLEANFILES = \
-# cls/ematch_grammar.c cls/ematch_grammar.h \
-# cls/ematch_syntax.c cls/ematch_syntax.h \
-# cls/pktloc_grammar.c cls/pktloc_grammar.h \
-# cls/pktloc_syntax.c cls/pktloc_syntax.h
-
-lib_LTLIBRARIES = \
- libnl-cli-3.la
-
-libnl_cli_3_la_LIBADD = ${top_builddir}/lib/libnl-3.la \
- ${top_builddir}/lib/libnl-route-3.la \
- ${top_builddir}/lib/libnl-nf-3.la \
- ${top_builddir}/lib/libnl-genl-3.la ${NL_LIBADD}
-
-libnl_cli_3_la_SOURCES = \
- utils.c addr.c ct.c link.c neigh.c rule.c route.c \
- tc.c qdisc.c class.c cls.c exp.c
-# cls/ematch_syntax.c cls/ematch_grammar.c cls/ematch.c
-# cls/pktloc_syntax.c cls/pktloc_grammar.c cls/utils.c
diff --git a/src/lib/addr.c b/src/lib/addr.c
index a9c137b2..5d39f7cb 100644
--- a/src/lib/addr.c
+++ b/src/lib/addr.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/addr.c Address Helpers
*
diff --git a/src/lib/class.c b/src/lib/class.c
index 96f60cd1..162e5427 100644
--- a/src/lib/class.c
+++ b/src/lib/class.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/class.c CLI Class Helpers
*
diff --git a/src/lib/cls.c b/src/lib/cls.c
index 86d775d2..a5ac9251 100644
--- a/src/lib/cls.c
+++ b/src/lib/cls.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/cls.c CLI Classifier Helpers
*
diff --git a/src/lib/ct.c b/src/lib/ct.c
index c9038780..e6732ae0 100644
--- a/src/lib/ct.c
+++ b/src/lib/ct.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/ct.c CLI Conntrack Helpers
*
diff --git a/src/lib/exp.c b/src/lib/exp.c
index a7a74f5a..732843f9 100644
--- a/src/lib/exp.c
+++ b/src/lib/exp.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/exp.c CLI Expectation Helpers
*
diff --git a/src/lib/link.c b/src/lib/link.c
index 5bce8240..ae367e4a 100644
--- a/src/lib/link.c
+++ b/src/lib/link.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/link.c CLI Link Helpers
*
@@ -31,12 +32,14 @@ struct rtnl_link *nl_cli_link_alloc(void)
return link;
}
-struct nl_cache *nl_cli_link_alloc_cache_family(struct nl_sock *sock, int family)
+struct nl_cache *nl_cli_link_alloc_cache_family_flags(struct nl_sock *sock,
+ int family,
+ unsigned int flags)
{
struct nl_cache *cache;
int err;
- if ((err = rtnl_link_alloc_cache(sock, family, &cache)) < 0)
+ if ((err = rtnl_link_alloc_cache_flags(sock, family, &cache, flags)) < 0)
nl_cli_fatal(err, "Unable to allocate link cache: %s",
nl_geterror(err));
@@ -45,11 +48,22 @@ struct nl_cache *nl_cli_link_alloc_cache_family(struct nl_sock *sock, int family
return cache;
}
+struct nl_cache *nl_cli_link_alloc_cache_family(struct nl_sock *sock, int family)
+{
+ return nl_cli_link_alloc_cache_family_flags(sock, family, 0);
+}
+
struct nl_cache *nl_cli_link_alloc_cache(struct nl_sock *sock)
{
return nl_cli_link_alloc_cache_family(sock, AF_UNSPEC);
}
+struct nl_cache *nl_cli_link_alloc_cache_flags(struct nl_sock *sock,
+ unsigned int flags)
+{
+ return nl_cli_link_alloc_cache_family_flags(sock, AF_UNSPEC, flags);
+}
+
void nl_cli_link_parse_family(struct rtnl_link *link, char *arg)
{
int family;
diff --git a/src/lib/neigh.c b/src/lib/neigh.c
index 4518e460..75862c7b 100644
--- a/src/lib/neigh.c
+++ b/src/lib/neigh.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/neigh.c CLI Neighbour Helpers
*
diff --git a/src/lib/qdisc.c b/src/lib/qdisc.c
index ccf7d269..ea047c2f 100644
--- a/src/lib/qdisc.c
+++ b/src/lib/qdisc.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/qdisc.c CLI QDisc Helpers
*
diff --git a/src/lib/route.c b/src/lib/route.c
index cd3e8978..9d0fbe83 100644
--- a/src/lib/route.c
+++ b/src/lib/route.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/route.c CLI Route Helpers
*
@@ -141,11 +142,13 @@ void nl_cli_route_parse_nexthop(struct rtnl_route *route, char *subopts,
NH_DEV,
NH_VIA,
NH_WEIGHT,
+ NH_AS,
};
static char *const tokens[] = {
"dev",
"via",
"weight",
+ "as",
NULL,
};
struct rtnl_nexthop *nh;
@@ -175,8 +178,20 @@ void nl_cli_route_parse_nexthop(struct rtnl_route *route, char *subopts,
break;
case NH_VIA:
- addr = nl_cli_addr_parse(arg,rtnl_route_get_family(route));
- rtnl_route_nh_set_gateway(nh, addr);
+ if (rtnl_route_get_family(route) == AF_MPLS) {
+ addr = nl_cli_addr_parse(arg, 0);
+ rtnl_route_nh_set_via(nh, addr);
+ } else {
+ addr = nl_cli_addr_parse(arg,rtnl_route_get_family(route));
+ rtnl_route_nh_set_gateway(nh, addr);
+ }
+ nl_addr_put(addr);
+ break;
+
+ case NH_AS:
+ addr = nl_cli_addr_parse(arg,
+ rtnl_route_get_family(route));
+ rtnl_route_nh_set_newdst(nh, addr);
nl_addr_put(addr);
break;
diff --git a/src/lib/rule.c b/src/lib/rule.c
index 96f1d4cc..213eca2a 100644
--- a/src/lib/rule.c
+++ b/src/lib/rule.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/rule.c CLI Routing Rule Helpers
*
diff --git a/src/lib/tc.c b/src/lib/tc.c
index dde729fa..5d3a2035 100644
--- a/src/lib/tc.c
+++ b/src/lib/tc.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/lib/tc.c CLI Traffic Control Helpers
*
diff --git a/src/lib/utils.c b/src/lib/utils.c
index e5eacdec..3aa2a90c 100644
--- a/src/lib/utils.c
+++ b/src/lib/utils.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/utils.c Utilities
*
@@ -22,6 +23,13 @@
*/
#include <netlink/cli/utils.h>
+#include <locale.h>
+
+#include "lib/defs.h"
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
/**
* Parse a text based 32 bit unsigned integer argument
@@ -70,7 +78,6 @@ void nl_cli_print_version(void)
void nl_cli_fatal(int err, const char *fmt, ...)
{
va_list ap;
- char buf[256];
fprintf(stderr, "Error: ");
@@ -79,8 +86,28 @@ void nl_cli_fatal(int err, const char *fmt, ...)
vfprintf(stderr, fmt, ap);
va_end(ap);
fprintf(stderr, "\n");
- } else
- fprintf(stderr, "%s\n", strerror_r(err, buf, sizeof(buf)));
+ } else {
+ char *buf;
+#ifdef HAVE_STRERROR_L
+ locale_t loc = newlocale(LC_MESSAGES_MASK, "", (locale_t)0);
+ if (loc == (locale_t)0) {
+ if (errno == ENOENT)
+ loc = newlocale(LC_MESSAGES_MASK,
+ "POSIX", (locale_t)0);
+ if (loc == (locale_t)0)
+ buf = "newlocale() failed";
+ }
+ if (loc != (locale_t)0)
+ buf = strerror_l(err, loc);
+#else
+ buf = strerror(err);
+#endif
+ fprintf(stderr, "%s\n", buf);
+#ifdef HAVE_STRERROR_L
+ if (loc != (locale_t)0)
+ freelocale(loc);
+#endif
+ }
exit(abs(err));
}
@@ -153,6 +180,7 @@ int nl_cli_confirm(struct nl_object *obj, struct nl_dump_params *params,
switch ((answer = tolower(buf[0]))) {
case '\n':
answer = default_yes ? 'y' : 'n';
+ /* fall through */
case 'y':
case 'n':
return answer == 'y';
@@ -180,17 +208,43 @@ struct nl_cache *nl_cli_alloc_cache(struct nl_sock *sock, const char *name,
return cache;
}
+struct nl_cache *nl_cli_alloc_cache_flags(struct nl_sock *sock,
+ const char *name, unsigned int flags,
+ int (*ac)(struct nl_sock *, struct nl_cache **,
+ unsigned int))
+{
+ struct nl_cache *cache;
+ int err;
+
+ if ((err = ac(sock, &cache, flags)) < 0)
+ nl_cli_fatal(err, "Unable to allocate %s cache: %s",
+ name, nl_geterror(err));
+
+ nl_cache_mngt_provide(cache);
+
+ return cache;
+}
+
void nl_cli_load_module(const char *prefix, const char *name)
{
char path[FILENAME_MAX+1];
- void *handle;
snprintf(path, sizeof(path), "%s/%s/%s.so",
PKGLIBDIR, prefix, name);
- if (!(handle = dlopen(path, RTLD_NOW)))
- nl_cli_fatal(ENOENT, "Unable to load module \"%s\": %s\n",
- path, dlerror());
+#ifdef HAVE_DLFCN_H
+ {
+ void *handle;
+
+ if (!(handle = dlopen(path, RTLD_NOW))) {
+ nl_cli_fatal(ENOENT, "Unable to load module \"%s\": %s\n",
+ path, dlerror());
+ }
+ }
+#else
+ nl_cli_fatal(ENOTSUP, "Unable to load module \"%s\": built without dynamic libraries support\n",
+ path);
+#endif
}
/** @} */
diff --git a/src/nf-ct-add.c b/src/nf-ct-add.c
index 8ad4c534..eec9b869 100644
--- a/src/nf-ct-add.c
+++ b/src/nf-ct-add.c
@@ -1,5 +1,6 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
- * src/nf-ct-list.c List Conntrack Entries
+ * src/nf-ct-add.c Add Conntrack Entry
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -14,6 +15,8 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/ct.h>
+#include <linux/rtnetlink.h>
+
static int quiet = 0;
static void print_usage(void)
diff --git a/src/nf-ct-events.c b/src/nf-ct-events.c
new file mode 100644
index 00000000..87f2da93
--- /dev/null
+++ b/src/nf-ct-events.c
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
+/*
+ * src/nf-ct-events.c Listen on Conntrack Events
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2018 Avast software
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/ct.h>
+
+#include <linux/netlink.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+struct private_nl_object
+{
+ int ce_refcnt;
+ struct nl_object_ops * ce_ops;
+ struct nl_cache * ce_cache;
+ struct nl_list_head ce_list;
+ int ce_msgtype;
+ int ce_flags;
+ uint64_t ce_mask;
+};
+
+static void nf_conntrack_parse_callback(struct nl_object *obj, void *opaque)
+{
+ struct nl_dump_params params = {
+ .dp_fd = stdout,
+ .dp_type = NL_DUMP_DETAILS,
+ };
+
+ nl_object_dump(obj, &params);
+}
+
+static int nf_conntrack_event_callback(struct nl_msg *msg, void *opaque)
+{
+ int err;
+ struct nlmsghdr *hdr = nlmsg_hdr(msg);
+
+ enum cntl_msg_types type = (enum cntl_msg_types) NFNL_MSG_TYPE(hdr->nlmsg_type);
+
+ int flags = hdr->nlmsg_flags;
+
+ if (type == IPCTNL_MSG_CT_DELETE) {
+ printf("DELETE ");
+ } else if (type == IPCTNL_MSG_CT_NEW) {
+ if (flags & (NLM_F_CREATE|NLM_F_EXCL)) {
+ printf("NEW ");
+ } else {
+ printf("UPDATE ");
+ }
+ } else {
+ printf("UNKNOWN ");
+ }
+
+ if ((err = nl_msg_parse(msg, &nf_conntrack_parse_callback, opaque)) < 0) {
+ nl_cli_fatal(err, "nl_msg_parse: %s", nl_geterror(err));
+ }
+ /* Continue with next event */
+ return NL_OK;
+}
+
+int main(int argc, char *argv[])
+{
+ struct nl_sock *socket;
+ int err;
+
+ socket = nl_cli_alloc_socket();
+ if (socket == NULL) {
+ nl_cli_fatal(ENOBUFS, "Unable to allocate netlink socket");
+ }
+
+ /*
+ * Disable sequence number checking.
+ * This is required to allow messages to be processed which were not requested by
+ * a preceding request message, e.g. netlink events.
+ */
+ nl_socket_disable_seq_check(socket);
+
+ /* subscribe conntrack events */
+ nl_join_groups(socket, NF_NETLINK_CONNTRACK_NEW |
+ NF_NETLINK_CONNTRACK_UPDATE |
+ NF_NETLINK_CONNTRACK_DESTROY |
+ NF_NETLINK_CONNTRACK_EXP_NEW |
+ NF_NETLINK_CONNTRACK_EXP_UPDATE |
+ NF_NETLINK_CONNTRACK_EXP_DESTROY);
+
+ nl_cli_connect(socket, NETLINK_NETFILTER);
+
+ nl_socket_modify_cb(socket, NL_CB_VALID, NL_CB_CUSTOM, &nf_conntrack_event_callback, 0);
+
+ while (1) {
+
+ errno = 0;
+ if ((err = nl_recvmsgs_default(socket)) < 0) {
+ switch (errno) {
+ case ENOBUFS:
+ // just print warning
+ fprintf(stderr, "Lost events because of ENOBUFS\n");
+ break;
+ case EAGAIN:
+ case EINTR:
+ // continue reading
+ break;
+ default:
+ nl_cli_fatal(err, "Failed to receive: %s", nl_geterror(err));
+ }
+ }
+ }
+}
diff --git a/src/nf-ct-list.c b/src/nf-ct-list.c
index 5f729988..c512027b 100644
--- a/src/nf-ct-list.c
+++ b/src/nf-ct-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nf-ct-list.c List Conntrack Entries
*
@@ -14,6 +15,8 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/ct.h>
+#include <linux/netlink.h>
+
static void print_usage(void)
{
printf(
@@ -54,9 +57,9 @@ int main(int argc, char *argv[])
.dp_type = NL_DUMP_LINE,
.dp_fd = stdout,
};
-
- ct = nl_cli_ct_alloc();
-
+
+ ct = nl_cli_ct_alloc();
+
for (;;) {
int c, optidx = 0;
enum {
@@ -95,7 +98,7 @@ int main(int argc, char *argv[])
{ "refcnt", 1, 0, ARG_REFCNT },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "46f:hvi:p:F:", long_opts, &optidx);
if (c == -1)
break;
@@ -124,7 +127,7 @@ int main(int argc, char *argv[])
case ARG_REFCNT: nl_cli_ct_parse_use(ct, optarg); break;
case ARG_FLAGS: nl_cli_ct_parse_status(ct, optarg); break;
}
- }
+ }
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_NETFILTER);
diff --git a/src/nf-exp-add.c b/src/nf-exp-add.c
index 4b7f9d98..1f71cd54 100644
--- a/src/nf-exp-add.c
+++ b/src/nf-exp-add.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nf-exp-add.c Create an expectation
*
@@ -16,6 +17,8 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/exp.h>
+#include <linux/netlink.h>
+
static int quiet = 0;
static void print_usage(void)
@@ -64,8 +67,8 @@ int main(int argc, char *argv[])
};
int err, nlflags = NLM_F_CREATE;
- exp = nl_cli_exp_alloc();
-
+ exp = nl_cli_exp_alloc();
+
for (;;) {
int c, optidx = 0;
enum {
@@ -86,12 +89,12 @@ int main(int argc, char *argv[])
ARG_MASK_SPORT,
ARG_MASK_DST,
ARG_MASK_DPORT,
- ARG_NAT_PROTO,
- ARG_NAT_SRC,
- ARG_NAT_SPORT,
- ARG_NAT_DST,
- ARG_NAT_DPORT,
- ARG_NAT_DIR,
+ ARG_NAT_PROTO,
+ ARG_NAT_SRC,
+ ARG_NAT_SPORT,
+ ARG_NAT_DST,
+ ARG_NAT_DPORT,
+ ARG_NAT_DIR,
ARG_TIMEOUT,
ARG_HELPER_NAME,
ARG_REPLACE,
@@ -118,19 +121,19 @@ int main(int argc, char *argv[])
{ "mask-sport", 1, 0, ARG_MASK_SPORT },
{ "mask-dst", 1, 0, ARG_MASK_DST },
{ "mask-dport", 1, 0, ARG_MASK_DPORT },
- { "nat-proto", 1, 0, ARG_NAT_PROTO },
- { "nat-src", 1, 0, ARG_NAT_SRC },
- { "nat-sport", 1, 0, ARG_NAT_SPORT },
- { "nat-dst", 1, 0, ARG_NAT_DST },
- { "nat-dport", 1, 0, ARG_NAT_DPORT },
- { "nat-dir", 1, 0, ARG_NAT_DIR },
+ { "nat-proto", 1, 0, ARG_NAT_PROTO },
+ { "nat-src", 1, 0, ARG_NAT_SRC },
+ { "nat-sport", 1, 0, ARG_NAT_SPORT },
+ { "nat-dst", 1, 0, ARG_NAT_DST },
+ { "nat-dport", 1, 0, ARG_NAT_DPORT },
+ { "nat-dir", 1, 0, ARG_NAT_DIR },
{ "family", 1, 0, 'F' },
{ "timeout", 1, 0, ARG_TIMEOUT },
{ "helper", 1, 0, ARG_HELPER_NAME },
{ "flags", 1, 0, ARG_FLAGS},
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "46f:hvi:p:F:", long_opts, &optidx);
if (c == -1)
break;
@@ -159,18 +162,18 @@ int main(int argc, char *argv[])
case ARG_MASK_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
case ARG_MASK_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
case ARG_MASK_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
- case ARG_NAT_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
- case ARG_NAT_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
- case ARG_NAT_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
- case ARG_NAT_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
- case ARG_NAT_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
- case ARG_NAT_DIR: nl_cli_exp_parse_nat_dir(exp, optarg); break;
+ case ARG_NAT_PROTO: nl_cli_exp_parse_l4protonum(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
+ case ARG_NAT_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
+ case ARG_NAT_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
+ case ARG_NAT_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
+ case ARG_NAT_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_NAT, optarg); break;
+ case ARG_NAT_DIR: nl_cli_exp_parse_nat_dir(exp, optarg); break;
case 'F': nl_cli_exp_parse_family(exp, optarg); break;
case ARG_TIMEOUT: nl_cli_exp_parse_timeout(exp, optarg); break;
case ARG_HELPER_NAME: nl_cli_exp_parse_helper_name(exp, optarg); break;
case ARG_FLAGS: nl_cli_exp_parse_flags(exp, optarg); break;
}
- }
+ }
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_NETFILTER);
diff --git a/src/nf-exp-delete.c b/src/nf-exp-delete.c
index 2ec45aea..c6e478c2 100644
--- a/src/nf-exp-delete.c
+++ b/src/nf-exp-delete.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nf-exp-delete.c Delete an expectation
*
@@ -15,6 +16,8 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/exp.h>
+#include <linux/rtnetlink.h>
+
static int quiet = 0;
static void print_usage(void)
@@ -63,8 +66,8 @@ int main(int argc, char *argv[])
};
int err, nlflags = 0;
- exp = nl_cli_exp_alloc();
-
+ exp = nl_cli_exp_alloc();
+
for (;;) {
int c, optidx = 0;
enum {
@@ -80,17 +83,17 @@ int main(int argc, char *argv[])
ARG_MASTER_SPORT,
ARG_MASTER_DST,
ARG_MASTER_DPORT,
- ARG_MASK_PROTO,
- ARG_MASK_SRC,
+ ARG_MASK_PROTO,
+ ARG_MASK_SRC,
ARG_MASK_SPORT,
ARG_MASK_DST,
ARG_MASK_DPORT,
ARG_TIMEOUT,
- ARG_HELPER_NAME,
+ ARG_HELPER_NAME,
ARG_FLAGS,
};
static struct option long_opts[] = {
- { "quiet", 0, 0, 'q' },
+ { "quiet", 0, 0, 'q' },
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'v' },
{ "id", 1, 0, 'i' },
@@ -105,17 +108,17 @@ int main(int argc, char *argv[])
{ "master-dst", 1, 0, ARG_MASTER_DST },
{ "master-dport", 1, 0, ARG_MASTER_DPORT },
{ "mask-proto", 1, 0, ARG_MASK_PROTO },
- { "mask-src", 1, 0, ARG_MASK_SRC },
- { "mask-sport", 1, 0, ARG_MASK_SPORT },
- { "mask-dst", 1, 0, ARG_MASK_DST },
- { "mask-dport", 1, 0, ARG_MASK_DPORT },
+ { "mask-src", 1, 0, ARG_MASK_SRC },
+ { "mask-sport", 1, 0, ARG_MASK_SPORT },
+ { "mask-dst", 1, 0, ARG_MASK_DST },
+ { "mask-dport", 1, 0, ARG_MASK_DPORT },
{ "family", 1, 0, 'F' },
{ "timeout", 1, 0, ARG_TIMEOUT },
{ "helper", 1, 0, ARG_HELPER_NAME },
- { "flags", 1, 0, ARG_FLAGS},
+ { "flags", 1, 0, ARG_FLAGS},
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "46f:hvi:p:F:", long_opts, &optidx);
if (c == -1)
break;
@@ -142,13 +145,13 @@ int main(int argc, char *argv[])
case ARG_MASK_SRC: nl_cli_exp_parse_src(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
case ARG_MASK_SPORT: nl_cli_exp_parse_src_port(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
case ARG_MASK_DST: nl_cli_exp_parse_dst(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
- case ARG_MASK_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
+ case ARG_MASK_DPORT: nl_cli_exp_parse_dst_port(exp, NFNL_EXP_TUPLE_MASK, optarg); break;
case 'F': nl_cli_exp_parse_family(exp, optarg); break;
case ARG_TIMEOUT: nl_cli_exp_parse_timeout(exp, optarg); break;
case ARG_HELPER_NAME: nl_cli_exp_parse_helper_name(exp, optarg); break;
case ARG_FLAGS: nl_cli_exp_parse_flags(exp, optarg); break;
}
- }
+ }
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_NETFILTER);
diff --git a/src/nf-exp-list.c b/src/nf-exp-list.c
index 1c6ec690..0993a98f 100644
--- a/src/nf-exp-list.c
+++ b/src/nf-exp-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nf-exp-list.c List Expectation Entries
*
@@ -15,6 +16,8 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/exp.h>
+#include <linux/netlink.h>
+
static void print_usage(void)
{
printf(
@@ -54,9 +57,9 @@ int main(int argc, char *argv[])
.dp_type = NL_DUMP_LINE,
.dp_fd = stdout,
};
-
- exp = nl_cli_exp_alloc();
-
+
+ exp = nl_cli_exp_alloc();
+
for (;;) {
int c, optidx = 0;
enum {
@@ -73,7 +76,7 @@ int main(int argc, char *argv[])
ARG_MASTER_DST,
ARG_MASTER_DPORT,
ARG_TIMEOUT,
- ARG_HELPER_NAME,
+ ARG_HELPER_NAME,
ARG_FLAGS,
};
static struct option long_opts[] = {
@@ -97,7 +100,7 @@ int main(int argc, char *argv[])
{ "flags", 1, 0, ARG_FLAGS},
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "46f:hvi:p:F:", long_opts, &optidx);
if (c == -1)
break;
@@ -125,7 +128,7 @@ int main(int argc, char *argv[])
case ARG_HELPER_NAME: nl_cli_exp_parse_helper_name(exp, optarg); break;
case ARG_FLAGS: nl_cli_exp_parse_flags(exp, optarg); break;
}
- }
+ }
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_NETFILTER);
diff --git a/src/nf-log.c b/src/nf-log.c
index 913ba163..c8a40bfa 100644
--- a/src/nf-log.c
+++ b/src/nf-log.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nf-log.c Monitor netfilter log events
*
@@ -13,10 +14,12 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/link.h>
-#include <linux/netfilter/nfnetlink_log.h>
#include <netlink/netfilter/nfnl.h>
#include <netlink/netfilter/log.h>
+#include <linux/netfilter/nfnetlink_log.h>
+#include <linux/netlink.h>
+
static struct nfnl_log *alloc_log(void)
{
struct nfnl_log *log;
@@ -52,9 +55,8 @@ int main(int argc, char *argv[])
{
struct nl_sock *nf_sock;
struct nl_sock *rt_sock;
- struct nl_cache *link_cache;
struct nfnl_log *log;
- enum nfnl_log_copy_mode copy_mode;
+ int copy_mode;
uint32_t copy_range;
int err;
int family;
@@ -116,7 +118,7 @@ int main(int argc, char *argv[])
rt_sock = nl_cli_alloc_socket();
nl_cli_connect(rt_sock, NETLINK_ROUTE);
- link_cache = nl_cli_link_alloc_cache(rt_sock);
+ nl_cli_link_alloc_cache(rt_sock);
while (1) {
fd_set rfds;
diff --git a/src/nf-monitor.c b/src/nf-monitor.c
index fe99af48..4afbdb2b 100644
--- a/src/nf-monitor.c
+++ b/src/nf-monitor.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nf-monitor.c Monitor netfilter events
*
@@ -14,6 +15,9 @@
#include <netlink/cli/utils.h>
#include <netlink/netfilter/nfnl.h>
+#include <linux/netlink.h>
+#include <linux/netfilter/nfnetlink.h>
+
static void obj_input(struct nl_object *obj, void *arg)
{
struct nl_dump_params dp = {
diff --git a/src/nf-queue.c b/src/nf-queue.c
index 922d9c8e..f46abc26 100644
--- a/src/nf-queue.c
+++ b/src/nf-queue.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nf-queue.c Monitor netfilter queue events
*
@@ -20,6 +21,8 @@
#include <netlink/netfilter/queue.h>
#include <netlink/netfilter/queue_msg.h>
+#include <linux/netlink.h>
+
static struct nl_sock *nf_sock;
static struct nfnl_queue *alloc_queue(void)
@@ -60,9 +63,8 @@ static int event_input(struct nl_msg *msg, void *arg)
int main(int argc, char *argv[])
{
struct nl_sock *rt_sock;
- struct nl_cache *link_cache;
struct nfnl_queue *queue;
- enum nfnl_queue_copy_mode copy_mode;
+ int copy_mode;
uint32_t copy_range;
int err = 1;
int family;
@@ -116,7 +118,7 @@ int main(int argc, char *argv[])
rt_sock = nl_cli_alloc_socket();
nl_cli_connect(rt_sock, NETLINK_ROUTE);
- link_cache = nl_cli_link_alloc_cache(rt_sock);
+ nl_cli_link_alloc_cache(rt_sock);
nl_socket_set_buffer_size(nf_sock, 1024*127, 1024*127);
diff --git a/src/nl-addr-add.c b/src/nl-addr-add.c
index 52995ec6..e6ebefe1 100644
--- a/src/nl-addr-add.c
+++ b/src/nl-addr-add.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-addr-add.c Add addresses
*
@@ -12,6 +13,8 @@
#include <netlink/cli/addr.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static int quiet = 0;
static void print_usage(void)
@@ -50,12 +53,12 @@ int main(int argc, char *argv[])
.dp_fd = stdout,
};
int err, nlflags = NLM_F_CREATE;
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
- addr = nl_cli_addr_alloc();
-
+ addr = nl_cli_addr_alloc();
+
for (;;) {
int c, optidx = 0;
enum {
@@ -84,7 +87,7 @@ int main(int argc, char *argv[])
{ "valid", 1, 0, ARG_VALID },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "qhva:d:", long_opts, &optidx);
if (c == -1)
break;
@@ -105,7 +108,7 @@ int main(int argc, char *argv[])
case ARG_PREFERRED: nl_cli_addr_parse_preferred(addr, optarg); break;
case ARG_VALID: nl_cli_addr_parse_valid(addr, optarg); break;
}
- }
+ }
if ((err = rtnl_addr_add(sock, addr, nlflags)) < 0)
nl_cli_fatal(err, "Unable to add address: %s",
@@ -114,7 +117,7 @@ int main(int argc, char *argv[])
if (!quiet) {
printf("Added ");
nl_object_dump(OBJ_CAST(addr), &dp);
- }
+ }
return 0;
}
diff --git a/src/nl-addr-delete.c b/src/nl-addr-delete.c
index 2849c017..9d017f42 100644
--- a/src/nl-addr-delete.c
+++ b/src/nl-addr-delete.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-addr-delete.c Delete addresses
*
@@ -12,6 +13,8 @@
#include <netlink/cli/addr.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static struct nl_sock *sock;
static int interactive = 0, default_yes = 0, quiet = 0;
static int deleted = 0;
@@ -108,7 +111,7 @@ int main(int argc, char *argv[])
{ "valid", 1, 0, ARG_VALID },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "iqhva:d:", long_opts, &optidx);
if (c == -1)
break;
@@ -129,7 +132,7 @@ int main(int argc, char *argv[])
case ARG_PREFERRED: nl_cli_addr_parse_preferred(addr, optarg); break;
case ARG_VALID: nl_cli_addr_parse_valid(addr, optarg); break;
}
- }
+ }
nl_cache_foreach_filter(addr_cache, OBJ_CAST(addr), delete_cb, NULL);
diff --git a/src/nl-addr-list.c b/src/nl-addr-list.c
index 20995a84..c5258bd4 100644
--- a/src/nl-addr-list.c
+++ b/src/nl-addr-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-addr-list.c List addresses
*
@@ -12,6 +13,8 @@
#include <netlink/cli/addr.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static void print_usage(void)
{
printf(
diff --git a/src/nl-class-add.c b/src/nl-class-add.c
index b9a17dc6..a1ccf4e8 100644
--- a/src/nl-class-add.c
+++ b/src/nl-class-add.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-class-add.c Add/Update/Replace Traffic Class
*
@@ -17,6 +18,8 @@
#include <netlink-private/route/tc-api.h>
+#include <linux/netlink.h>
+
static int quiet = 0;
static void print_usage(void)
@@ -62,15 +65,15 @@ int main(int argc, char *argv[])
struct rtnl_tc_ops *ops;
int err, flags = NLM_F_CREATE | NLM_F_EXCL;
char *kind, *id = NULL;
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
- class = nl_cli_class_alloc();
+ class = nl_cli_class_alloc();
tc = (struct rtnl_tc *) class;
-
+
for (;;) {
int c, optidx = 0;
enum {
@@ -96,7 +99,7 @@ int main(int argc, char *argv[])
{ "linktype", 1, 0, ARG_LINKTYPE },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "+qhvd:p:i:",
long_opts, &optidx);
if (c == -1)
@@ -116,7 +119,7 @@ int main(int argc, char *argv[])
case ARG_OVERHEAD: nl_cli_tc_parse_overhead(tc, optarg); break;
case ARG_LINKTYPE: nl_cli_tc_parse_linktype(tc, optarg); break;
}
- }
+ }
if (optind >= argc)
print_usage();
@@ -146,7 +149,7 @@ int main(int argc, char *argv[])
if (!quiet) {
printf("Adding ");
nl_object_dump(OBJ_CAST(class), &dp);
- }
+ }
if ((err = rtnl_class_add(sock, class, flags)) < 0)
nl_cli_fatal(EINVAL, "Unable to add class: %s", nl_geterror(err));
diff --git a/src/nl-class-delete.c b/src/nl-class-delete.c
index 37657a47..56278210 100644
--- a/src/nl-class-delete.c
+++ b/src/nl-class-delete.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-class-delete.c Delete Traffic Classes
*
@@ -13,6 +14,8 @@
#include <netlink/cli/class.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0;
static struct nl_sock *sock;
@@ -70,13 +73,13 @@ int main(int argc, char *argv[])
struct rtnl_class *class;
struct rtnl_tc *tc;
struct nl_cache *link_cache, *class_cache;
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
- class = nl_cli_class_alloc();
+ class = nl_cli_class_alloc();
tc = (struct rtnl_tc *) class;
-
+
for (;;) {
int c, optidx = 0;
enum {
@@ -95,7 +98,7 @@ int main(int argc, char *argv[])
{ "kind", 1, 0, 'k' },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "qhvd:p:i:k:", long_opts, &optidx);
if (c == -1)
break;
@@ -112,7 +115,7 @@ int main(int argc, char *argv[])
case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break;
case 'k': nl_cli_tc_parse_kind(tc, optarg); break;
}
- }
+ }
if (!rtnl_tc_get_ifindex(tc))
nl_cli_fatal(EINVAL, "You must specify a network device (--dev=XXX)");
diff --git a/src/nl-class-list.c b/src/nl-class-list.c
index c2423fbf..0ce4ab24 100644
--- a/src/nl-class-list.c
+++ b/src/nl-class-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-class-list.c List Traffic Classes
*
@@ -14,6 +15,8 @@
#include <netlink/cli/class.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static struct nl_sock *sock;
static struct nl_dump_params params = {
@@ -65,15 +68,15 @@ int main(int argc, char *argv[])
struct rtnl_tc *tc;
struct nl_cache *link_cache;
int ifindex;
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
- class = nl_cli_class_alloc();
+ class = nl_cli_class_alloc();
tc = (struct rtnl_tc *) class;
params.dp_fd = stdout;
-
+
for (;;) {
int c, optidx = 0;
enum {
@@ -91,7 +94,7 @@ int main(int argc, char *argv[])
{ "kind", 1, 0, 'k' },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "hvd:p:i:k:", long_opts, &optidx);
if (c == -1)
break;
@@ -106,11 +109,11 @@ int main(int argc, char *argv[])
case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break;
case 'k': nl_cli_tc_parse_kind(tc, optarg); break;
}
- }
+ }
if ((ifindex = rtnl_tc_get_ifindex(tc)))
__dump_class(ifindex, class);
- else
+ else
nl_cache_foreach(link_cache, dump_class, class);
return 0;
diff --git a/src/nl-classid-lookup.c b/src/nl-classid-lookup.c
index 1d45d0b2..4ddc8429 100644
--- a/src/nl-classid-lookup.c
+++ b/src/nl-classid-lookup.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-classid-lookup.c Lookup classid
*
@@ -10,6 +11,7 @@
*/
#include <netlink/cli/utils.h>
+#include <linux/pkt_sched.h>
static void print_usage(void)
{
@@ -48,7 +50,7 @@ int main(int argc, char *argv[])
{ "raw", 0, 0, ARG_RAW },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "hvr", long_opts, &optidx);
if (c == -1)
break;
@@ -59,7 +61,7 @@ int main(int argc, char *argv[])
case 'r': reverse = 1; break;
case ARG_RAW: raw = 1; break;
}
- }
+ }
if (optind >= argc)
print_usage();
diff --git a/src/nl-cls-add.c b/src/nl-cls-add.c
index 6acb3202..c2ad7173 100644
--- a/src/nl-cls-add.c
+++ b/src/nl-cls-add.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-cls-add.c Add classifier
*
@@ -15,6 +16,8 @@
#include <netlink-private/route/tc-api.h>
+#include <linux/netlink.h>
+
static int quiet = 0;
static void print_usage(void)
@@ -31,7 +34,7 @@ static void print_usage(void)
" -d, --dev=DEV Network device the classifier should be attached to.\n"
" -i, --id=ID ID of new classifier (default: auto-generated)\n"
" -p, --parent=ID ID of parent { root | ingress | class-ID }\n"
-" --protocol=PROTO Protocol to match (default: all)\n"
+" --proto=PROTO Protocol to match (default: all)\n"
" --prio=PRIO Priority (default: 0)\n"
" --mtu=SIZE Overwrite MTU (default: MTU of network device)\n"
" --mpu=SIZE Minimum packet size on the link (default: 0).\n"
@@ -62,15 +65,15 @@ int main(int argc, char *argv[])
struct rtnl_tc_ops *ops;
int err, flags = NLM_F_CREATE | NLM_F_EXCL;
char *kind, *id = NULL;
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
- cls = nl_cli_cls_alloc();
+ cls = nl_cli_cls_alloc();
tc = (struct rtnl_tc *) cls;
-
+
for (;;) {
int c, optidx = 0;
enum {
@@ -100,7 +103,7 @@ int main(int argc, char *argv[])
{ "linktype", 1, 0, ARG_LINKTYPE },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "+qhvd:p:i:",
long_opts, &optidx);
if (c == -1)
@@ -124,7 +127,7 @@ int main(int argc, char *argv[])
rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg));
break;
}
- }
+ }
if (optind >= argc)
print_usage();
@@ -154,7 +157,7 @@ int main(int argc, char *argv[])
if (!quiet) {
printf("Adding ");
nl_object_dump(OBJ_CAST(cls), &dp);
- }
+ }
if ((err = rtnl_cls_add(sock, cls, flags)) < 0)
nl_cli_fatal(EINVAL, "Unable to add classifier: %s", nl_geterror(err));
diff --git a/src/nl-cls-delete.c b/src/nl-cls-delete.c
index 2b3db1f1..a2a93a72 100644
--- a/src/nl-cls-delete.c
+++ b/src/nl-cls-delete.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-cls-delete.c Delete Classifier
*
@@ -13,6 +14,8 @@
#include <netlink/cli/cls.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0;
static struct nl_sock *sock;
@@ -32,7 +35,7 @@ static void print_usage(void)
" -p, --parent=ID Identifier of parent qdisc/class.\n"
" -i, --id=ID Identifier\n"
" -k, --kind=NAME Kind of classifier (e.g. basic, u32, fw)\n"
-" --protocol=PROTO Protocol to match (default: all)\n"
+" --proto=PROTO Protocol to match (default: all)\n"
" --prio=PRIO Priority (default: 0)\n"
"\n"
"EXAMPLE\n"
@@ -91,13 +94,13 @@ int main(int argc, char *argv[])
struct rtnl_tc *tc;
struct nl_cache *link_cache;
int ifindex;
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
- cls = nl_cli_cls_alloc();
+ cls = nl_cli_cls_alloc();
tc = (struct rtnl_tc *) cls;
-
+
for (;;) {
int c, optidx = 0;
enum {
@@ -120,7 +123,7 @@ int main(int argc, char *argv[])
{ "prio", 1, 0, ARG_PRIO },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "qhvd:p:i:k:", long_opts, &optidx);
if (c == -1)
break;
@@ -141,11 +144,11 @@ int main(int argc, char *argv[])
rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg));
break;
}
- }
+ }
if ((ifindex = rtnl_tc_get_ifindex(tc)))
__delete_link(ifindex, cls);
- else
+ else
nl_cache_foreach(link_cache, delete_link, cls);
if (!quiet)
diff --git a/src/nl-cls-list.c b/src/nl-cls-list.c
index 50725850..5d4faa0f 100644
--- a/src/nl-cls-list.c
+++ b/src/nl-cls-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-cls-list.c List classifiers
*
@@ -14,6 +15,8 @@
#include <netlink/cli/cls.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static struct nl_sock *sock;
static struct nl_dump_params params = {
@@ -35,7 +38,7 @@ static void print_usage(void)
" -p, --parent=ID Identifier of parent class.\n"
" -i, --id=ID Identifier.\n"
" -k, --kind=NAME Kind of classifier (e.g. basic, u32, fw)\n"
-" --protocol=PROTO Protocol to match (default: all)\n"
+" --proto=PROTO Protocol to match (default: all)\n"
" --prio=PRIO Priority (default: 0)\n"
"\n"
"EXAMPLE\n"
@@ -69,15 +72,15 @@ int main(int argc, char *argv[])
struct rtnl_tc *tc;
struct nl_cache *link_cache;
int ifindex;
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
- cls = nl_cli_cls_alloc();
+ cls = nl_cli_cls_alloc();
tc = (struct rtnl_tc *) cls;
params.dp_fd = stdout;
-
+
for (;;) {
int c, optidx = 0;
enum {
@@ -99,7 +102,7 @@ int main(int argc, char *argv[])
{ "prio", 1, 0, ARG_PRIO },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "hvd:p:i:k:", long_opts, &optidx);
if (c == -1)
break;
@@ -118,11 +121,11 @@ int main(int argc, char *argv[])
rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg));
break;
}
- }
+ }
if ((ifindex = rtnl_tc_get_ifindex(tc)))
__dump_link(ifindex, cls);
- else
+ else
nl_cache_foreach(link_cache, dump_link, cls);
return 0;
diff --git a/src/nl-fib-lookup.c b/src/nl-fib-lookup.c
index 705cf329..a6496872 100644
--- a/src/nl-fib-lookup.c
+++ b/src/nl-fib-lookup.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-fib-lookup.c FIB Route Lookup
*
@@ -11,6 +12,8 @@
#include <netlink/cli/utils.h>
+#include <linux/rtnetlink.h>
+
static void print_usage(void)
{
printf(
diff --git a/src/nl-link-enslave.c b/src/nl-link-enslave.c
index 2b5d47db..4e368c38 100644
--- a/src/nl-link-enslave.c
+++ b/src/nl-link-enslave.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-link-enslave.c Enslave a link
*
@@ -13,6 +14,8 @@
#include <netlink/cli/link.h>
#include <netlink/route/link/bonding.h>
+#include <linux/netlink.h>
+
int main(int argc, char *argv[])
{
struct nl_sock *sock;
diff --git a/src/nl-link-ifindex2name.c b/src/nl-link-ifindex2name.c
index 68e5158a..0cb3cbe2 100644
--- a/src/nl-link-ifindex2name.c
+++ b/src/nl-link-ifindex2name.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-link-ifindex2name.c Transform a interface index to its name
*
@@ -12,6 +13,8 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static void print_usage(void)
{
printf("Usage: nl-link-ifindex2name <ifindex>\n");
diff --git a/src/nl-link-list.c b/src/nl-link-list.c
index b5c98b40..d3820762 100644
--- a/src/nl-link-list.c
+++ b/src/nl-link-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-link-dump.c Dump link attributes
*
@@ -12,6 +13,8 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static void print_usage(void)
{
printf(
diff --git a/src/nl-link-name2ifindex.c b/src/nl-link-name2ifindex.c
index b8ae4bcd..d3e83998 100644
--- a/src/nl-link-name2ifindex.c
+++ b/src/nl-link-name2ifindex.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-link-name2ifindex.c Transform a interface name to its index
*
@@ -12,6 +13,8 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static void print_usage(void)
{
printf("Usage: nl-link-name2ifindex <name>\n");
diff --git a/src/nl-link-release.c b/src/nl-link-release.c
index 4c9f15a5..abe8cdb7 100644
--- a/src/nl-link-release.c
+++ b/src/nl-link-release.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-link-release.c release a link
*
@@ -13,6 +14,8 @@
#include <netlink/cli/link.h>
#include <netlink/route/link/bonding.h>
+#include <linux/netlink.h>
+
int main(int argc, char *argv[])
{
struct nl_sock *sock;
diff --git a/src/nl-link-set.c b/src/nl-link-set.c
index bbb60f97..fc0f5a78 100644
--- a/src/nl-link-set.c
+++ b/src/nl-link-set.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-link-set.c Set link attributes
*
@@ -12,6 +13,9 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/link.h>
+#include <linux/if.h>
+#include <linux/netlink.h>
+
static struct nl_sock *sock;
static int quiet = 0;
diff --git a/src/nl-link-stats.c b/src/nl-link-stats.c
index 4dfca867..85719c1c 100644
--- a/src/nl-link-stats.c
+++ b/src/nl-link-stats.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-link-stats.c Retrieve link statistics
*
@@ -12,6 +13,8 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static void print_usage(void)
{
printf(
@@ -34,7 +37,7 @@ static void list_stat_names(void)
char buf[64];
int i;
- for (i = 0; i < RTNL_LINK_STATS_MAX; i++)
+ for (i = 0; i <= RTNL_LINK_STATS_MAX; i++)
printf("%s\n", rtnl_link_stat2str(i, buf, sizeof(buf)));
exit(0);
@@ -59,7 +62,7 @@ static void dump_stats(struct nl_object *obj, void *arg)
if (optind >= gargc) {
int i;
- for (i = 0; i < RTNL_LINK_STATS_MAX; i++)
+ for (i = 0; i <= RTNL_LINK_STATS_MAX; i++)
dump_stat(link, i);
} else {
while (optind < gargc) {
diff --git a/src/nl-list-caches.c b/src/nl-list-caches.c
index 853d8a40..c59f95b1 100644
--- a/src/nl-list-caches.c
+++ b/src/nl-list-caches.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* nl-list-caches.c List registered cache types
*
diff --git a/src/nl-list-sockets.c b/src/nl-list-sockets.c
index c2fa1cdb..e7d47038 100644
--- a/src/nl-list-sockets.c
+++ b/src/nl-list-sockets.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* nl-list-sockets.c Pretty-print /proc/net/netlink
*
@@ -18,7 +19,7 @@ int main(int argc, char *argv[])
FILE *fd;
char buf[2048], p[64];
- fd = fopen(PROC_NETLINK, "r");
+ fd = fopen(PROC_NETLINK, "re");
if (fd == NULL) {
perror("fopen");
return -1;
diff --git a/src/nl-monitor.c b/src/nl-monitor.c
index fdf64977..a6f21b4a 100644
--- a/src/nl-monitor.c
+++ b/src/nl-monitor.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-monitor.c Monitor events
*
@@ -12,71 +13,105 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/link.h>
+#include <linux/rtnetlink.h>
+
+static const struct {
+ enum rtnetlink_groups gr_id;
+ const char* gr_name;
+} known_groups[] = {
+ { RTNLGRP_LINK, "link" },
+ { RTNLGRP_NOTIFY, "notify" },
+ { RTNLGRP_NEIGH, "neigh" },
+ { RTNLGRP_TC, "tc" },
+ { RTNLGRP_IPV4_IFADDR, "ipv4-ifaddr" },
+ { RTNLGRP_IPV4_MROUTE, "ipv4-mroute" },
+ { RTNLGRP_IPV4_ROUTE, "ipv4-route" },
+ { RTNLGRP_IPV6_IFADDR, "ipv6-ifaddr" },
+ { RTNLGRP_IPV6_MROUTE, "ipv6-mroute" },
+ { RTNLGRP_IPV6_ROUTE, "ipv6-route" },
+ { RTNLGRP_IPV6_IFINFO, "ipv6-ifinfo" },
+ { RTNLGRP_DECnet_IFADDR, "decnet-ifaddr" },
+ { RTNLGRP_DECnet_ROUTE, "decnet-route" },
+ { RTNLGRP_IPV6_PREFIX, "ipv6-prefix" },
+ { RTNLGRP_IPV4_NETCONF, "ipv4-netconf" },
+ { RTNLGRP_IPV6_NETCONF, "ipv6-netconf" },
+ { RTNLGRP_MPLS_NETCONF, "mpls-netconf" },
+ { RTNLGRP_NONE, NULL }
+};
+
static void obj_input(struct nl_object *obj, void *arg)
{
- struct nl_dump_params dp = {
- .dp_type = NL_DUMP_STATS,
- .dp_fd = stdout,
- .dp_dump_msgtype = 1,
- };
-
- nl_object_dump(obj, &dp);
+ nl_object_dump(obj, arg);
}
static int event_input(struct nl_msg *msg, void *arg)
{
- if (nl_msg_parse(msg, &obj_input, NULL) < 0)
+ if (nl_msg_parse(msg, &obj_input, arg) < 0)
fprintf(stderr, "<<EVENT>> Unknown message type\n");
/* Exit nl_recvmsgs_def() and return to the main select() */
return NL_STOP;
}
+static void print_usage(void)
+{
+ int i;
+
+ printf(
+ "Usage: nl-monitor [OPTION] [<groups>]\n"
+ "\n"
+ "Options\n"
+ " -f, --format=TYPE Output format { brief | details | stats }\n"
+ " -h, --help Show this help.\n"
+ "\n"
+ );
+ printf("Known groups:");
+ for (i = 0; known_groups[i].gr_id != RTNLGRP_NONE; i++)
+ printf(" %s", known_groups[i].gr_name);
+ printf("\n");
+ exit(0);
+}
+
int main(int argc, char *argv[])
{
+ struct nl_dump_params dp = {
+ .dp_type = NL_DUMP_STATS,
+ .dp_fd = stdout,
+ .dp_dump_msgtype = 1,
+ };
+
struct nl_sock *sock;
- struct nl_cache *link_cache;
int err = 1;
int i, idx;
- static const struct {
- enum rtnetlink_groups gr_id;
- const char* gr_name;
- } known_groups[] = {
- { RTNLGRP_LINK, "link" },
- { RTNLGRP_NOTIFY, "notify" },
- { RTNLGRP_NEIGH, "neigh" },
- { RTNLGRP_TC, "tc" },
- { RTNLGRP_IPV4_IFADDR, "ipv4-ifaddr" },
- { RTNLGRP_IPV4_MROUTE, "ipv4-mroute" },
- { RTNLGRP_IPV4_ROUTE, "ipv4-route" },
- { RTNLGRP_IPV6_IFADDR, "ipv6-ifaddr" },
- { RTNLGRP_IPV6_MROUTE, "ipv6-mroute" },
- { RTNLGRP_IPV6_ROUTE, "ipv6-route" },
- { RTNLGRP_IPV6_IFINFO, "ipv6-ifinfo" },
- { RTNLGRP_DECnet_IFADDR, "decnet-ifaddr" },
- { RTNLGRP_DECnet_ROUTE, "decnet-route" },
- { RTNLGRP_IPV6_PREFIX, "ipv6-prefix" },
- { RTNLGRP_NONE, NULL }
- };
-
sock = nl_cli_alloc_socket();
nl_socket_disable_seq_check(sock);
- nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, NULL);
-
- if (argc > 1 && !strcasecmp(argv[1], "-h")) {
- printf("Usage: nl-monitor [<groups>]\n");
-
- printf("Known groups:");
- for (i = 0; known_groups[i].gr_id != RTNLGRP_NONE; i++)
- printf(" %s", known_groups[i].gr_name);
- printf("\n");
- return 2;
+ nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, event_input, &dp);
+
+ for (;;) {
+ int c, optidx = 0;
+ static struct option long_opts[] = {
+ { "format", 1, 0, 'f' },
+ { 0, 0, 0, 0 }
+ };
+
+ c = getopt_long(argc, argv, "f:h", long_opts, &optidx);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'f':
+ dp.dp_type = nl_cli_parse_dumptype(optarg);
+ break;
+ default:
+ print_usage();
+ break;
+ }
}
nl_cli_connect(sock, NETLINK_ROUTE);
- for (idx = 1; argc > idx; idx++) {
+ for (idx = optind; argc > idx; idx++) {
for (i = 0; known_groups[i].gr_id != RTNLGRP_NONE; i++) {
if (!strcmp(argv[idx], known_groups[i].gr_name)) {
@@ -92,7 +127,7 @@ int main(int argc, char *argv[])
fprintf(stderr, "Warning: Unknown group: %s\n", argv[idx]);
}
- link_cache = nl_cli_link_alloc_cache(sock);
+ nl_cli_link_alloc_cache(sock);
while (1) {
fd_set rfds;
diff --git a/src/nl-neigh-add.c b/src/nl-neigh-add.c
index 4cddabe4..585639a0 100644
--- a/src/nl-neigh-add.c
+++ b/src/nl-neigh-add.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/ nl-neigh-add.c Add a neighbour
*
@@ -13,6 +14,8 @@
#include <netlink/cli/neigh.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static int quiet = 0;
static void print_usage(void)
@@ -51,12 +54,12 @@ int main(int argc, char *argv[])
.dp_fd = stdout,
};
int err, ok = 0, nlflags = NLM_F_REPLACE | NLM_F_CREATE;
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
- neigh = nl_cli_neigh_alloc();
-
+ neigh = nl_cli_neigh_alloc();
+
for (;;) {
int c, optidx = 0;
enum {
@@ -76,7 +79,7 @@ int main(int argc, char *argv[])
{ "state", 1, 0, ARG_STATE },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "qhva:l:d:", long_opts, &optidx);
if (c == -1)
break;
@@ -92,7 +95,7 @@ int main(int argc, char *argv[])
case 'd': nl_cli_neigh_parse_dev(neigh, link_cache, optarg); break;
case ARG_STATE: nl_cli_neigh_parse_state(neigh, optarg); break;
}
- }
+ }
if (!ok)
print_usage();
@@ -104,7 +107,7 @@ int main(int argc, char *argv[])
if (!quiet) {
printf("Added ");
nl_object_dump(OBJ_CAST(neigh), &dp);
- }
+ }
return 0;
}
diff --git a/src/nl-neigh-delete.c b/src/nl-neigh-delete.c
index c4186088..826c1c5c 100644
--- a/src/nl-neigh-delete.c
+++ b/src/nl-neigh-delete.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-neigh-delete.c Delete a neighbour
*
@@ -13,6 +14,8 @@
#include <netlink/cli/neigh.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0;
static struct nl_sock *sock;
@@ -67,13 +70,13 @@ int main(int argc, char *argv[])
{
struct rtnl_neigh *neigh;
struct nl_cache *link_cache, *neigh_cache;
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
neigh_cache = nl_cli_neigh_alloc_cache(sock);
- neigh = nl_cli_neigh_alloc();
-
+ neigh = nl_cli_neigh_alloc();
+
for (;;) {
int c, optidx = 0;
enum {
@@ -94,7 +97,7 @@ int main(int argc, char *argv[])
{ "state", 1, 0, ARG_STATE },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "qhva:l:d:", long_opts, &optidx);
if (c == -1)
break;
@@ -111,7 +114,7 @@ int main(int argc, char *argv[])
case ARG_FAMILY: nl_cli_neigh_parse_family(neigh, optarg); break;
case ARG_STATE: nl_cli_neigh_parse_state(neigh, optarg); break;
}
- }
+ }
nl_cache_foreach_filter(neigh_cache, OBJ_CAST(neigh), delete_cb, NULL);
diff --git a/src/nl-neigh-list.c b/src/nl-neigh-list.c
index ebf54863..a9262083 100644
--- a/src/nl-neigh-list.c
+++ b/src/nl-neigh-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-neigh-list.c List Neighbours
*
@@ -13,6 +14,8 @@
#include <netlink/cli/neigh.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static void print_usage(void)
{
printf(
@@ -42,13 +45,13 @@ int main(int argc, char *argv[])
.dp_type = NL_DUMP_LINE,
.dp_fd = stdout,
};
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
- link_cache = nl_cli_link_alloc_cache(sock);
+ link_cache = nl_cli_link_alloc_cache_flags(sock, NL_CACHE_AF_ITER);
neigh_cache = nl_cli_neigh_alloc_cache(sock);
- neigh = nl_cli_neigh_alloc();
-
+ neigh = nl_cli_neigh_alloc();
+
for (;;) {
int c, optidx = 0;
enum {
@@ -66,7 +69,7 @@ int main(int argc, char *argv[])
{ "state", 1, 0, ARG_STATE },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "f:hva:l:d:", long_opts, &optidx);
if (c == -1)
break;
@@ -81,9 +84,14 @@ int main(int argc, char *argv[])
case ARG_FAMILY: nl_cli_neigh_parse_family(neigh, optarg); break;
case ARG_STATE: nl_cli_neigh_parse_state(neigh, optarg); break;
}
- }
+ }
nl_cache_dump_filter(neigh_cache, &params, OBJ_CAST(neigh));
+ rtnl_neigh_put(neigh);
+ nl_cache_put(neigh_cache);
+ nl_cache_put(link_cache);
+ nl_socket_free(sock);
+
return 0;
}
diff --git a/src/nl-neightbl-list.c b/src/nl-neightbl-list.c
index 5010b92d..10d7ed41 100644
--- a/src/nl-neightbl-list.c
+++ b/src/nl-neightbl-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-neightbl-list.c Dump neighbour tables
*
@@ -12,6 +13,8 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static void print_usage(void)
{
printf(
@@ -28,18 +31,18 @@ static void print_usage(void)
int main(int argc, char *argv[])
{
struct nl_sock *sock;
- struct nl_cache *link_cache, *neightbl_cache;
+ struct nl_cache *neightbl_cache;
struct nl_dump_params params = {
.dp_type = NL_DUMP_LINE,
.dp_fd = stdout,
};
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
- link_cache = nl_cli_link_alloc_cache(sock);
+ nl_cli_link_alloc_cache(sock);
neightbl_cache = nl_cli_alloc_cache(sock, "neighbour table",
rtnl_neightbl_alloc_cache);
-
+
for (;;) {
int c, optidx = 0;
static struct option long_opts[] = {
@@ -48,7 +51,7 @@ int main(int argc, char *argv[])
{ "version", 0, 0, 'v' },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "f:hv", long_opts, &optidx);
if (c == -1)
break;
@@ -58,7 +61,7 @@ int main(int argc, char *argv[])
case 'h': print_usage(); break;
case 'v': nl_cli_print_version(); break;
}
- }
+ }
nl_cache_dump(neightbl_cache, &params);
diff --git a/src/nl-pktloc-lookup.c b/src/nl-pktloc-lookup.c
index 17c867b5..8b1272cc 100644
--- a/src/nl-pktloc-lookup.c
+++ b/src/nl-pktloc-lookup.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-pktloc-lookup.c Lookup packet location alias
*
@@ -11,6 +12,7 @@
#include <netlink/cli/utils.h>
#include <netlink/route/pktloc.h>
+#include <linux/tc_ematch/tc_em_cmp.h>
static void print_usage(void)
{
@@ -122,7 +124,7 @@ int main(int argc, char *argv[])
{ "u32", 1, 0, ARG_U32 },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "hvl", long_opts, &optidx);
if (c == -1)
break;
@@ -136,7 +138,7 @@ int main(int argc, char *argv[])
uvalue = nl_cli_parse_u32(optarg);
break;
}
- }
+ }
if (optind >= argc)
print_usage();
diff --git a/src/nl-qdisc-add.c b/src/nl-qdisc-add.c
index c2a7c9f7..38903f3e 100644
--- a/src/nl-qdisc-add.c
+++ b/src/nl-qdisc-add.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-qdisc-add.c Add Queueing Discipline
*
@@ -16,6 +17,8 @@
#include <netlink-private/route/tc-api.h>
+#include <linux/netlink.h>
+
static int quiet = 0;
static void print_usage(void)
@@ -59,15 +62,15 @@ int main(int argc, char *argv[])
struct rtnl_tc_ops *ops;
int err, flags = NLM_F_CREATE | NLM_F_EXCL;
char *kind, *id = NULL;
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
- qdisc = nl_cli_qdisc_alloc();
+ qdisc = nl_cli_qdisc_alloc();
tc = (struct rtnl_tc *) qdisc;
-
+
for (;;) {
int c, optidx = 0;
enum {
@@ -89,7 +92,7 @@ int main(int argc, char *argv[])
{ "update-only", 0, 0, ARG_UPDATE_ONLY },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "+qhvd:p:i:",
long_opts, &optidx);
if (c == -1)
@@ -107,7 +110,7 @@ int main(int argc, char *argv[])
case ARG_UPDATE_ONLY: flags = 0; break;
case ARG_REPLACE_ONLY: flags = NLM_F_REPLACE; break;
}
- }
+ }
if (optind >= argc)
print_usage();
@@ -137,7 +140,7 @@ int main(int argc, char *argv[])
if (!quiet) {
printf("Adding ");
nl_object_dump(OBJ_CAST(qdisc), &dp);
- }
+ }
if ((err = rtnl_qdisc_add(sock, qdisc, flags)) < 0)
nl_cli_fatal(EINVAL, "Unable to add qdisc: %s", nl_geterror(err));
diff --git a/src/nl-qdisc-delete.c b/src/nl-qdisc-delete.c
index 2f945bb2..7c5926b7 100644
--- a/src/nl-qdisc-delete.c
+++ b/src/nl-qdisc-delete.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-qdisc-delete.c Delete Queuing Disciplines
*
@@ -14,6 +15,8 @@
#include <netlink/cli/qdisc.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static int quiet = 0, default_yes = 0, deleted = 0, interactive = 0;
static struct nl_sock *sock;
@@ -71,14 +74,14 @@ int main(int argc, char *argv[])
struct rtnl_tc *tc;
struct nl_cache *link_cache, *qdisc_cache;
int nfilter = 0;
-
+
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
qdisc_cache = nl_cli_qdisc_alloc_cache(sock);
- qdisc = nl_cli_qdisc_alloc();
+ qdisc = nl_cli_qdisc_alloc();
tc = (struct rtnl_tc *) qdisc;
-
+
for (;;) {
int c, optidx = 0;
enum {
@@ -97,7 +100,7 @@ int main(int argc, char *argv[])
{ "kind", 1, 0, 'k' },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "qhvd:p:i:k:", long_opts, &optidx);
if (c == -1)
break;
@@ -126,7 +129,7 @@ int main(int argc, char *argv[])
nl_cli_tc_parse_kind(tc, optarg);
break;
}
- }
+ }
if (nfilter == 0 && !interactive && !default_yes) {
nl_cli_fatal(EINVAL,
diff --git a/src/nl-qdisc-list.c b/src/nl-qdisc-list.c
index 5b0a3f00..6796ca52 100644
--- a/src/nl-qdisc-list.c
+++ b/src/nl-qdisc-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-qdisc-list.c List Queueing Disciplines
*
@@ -16,6 +17,9 @@
#include <netlink/cli/cls.h>
#include <netlink/cli/link.h>
+#include <linux/pkt_sched.h>
+#include <linux/netlink.h>
+
#define NUM_INDENT 4
static struct nl_sock *sock;
@@ -129,15 +133,15 @@ int main(int argc, char *argv[])
struct rtnl_qdisc *qdisc;
struct rtnl_tc *tc;
struct nl_cache *link_cache, *qdisc_cache;
-
+
params.dp_fd = stdout;
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
link_cache = nl_cli_link_alloc_cache(sock);
qdisc_cache = nl_cli_qdisc_alloc_cache(sock);
- qdisc = nl_cli_qdisc_alloc();
+ qdisc = nl_cli_qdisc_alloc();
tc = (struct rtnl_tc *) qdisc;
-
+
for (;;) {
int c, optidx = 0;
enum {
@@ -156,7 +160,7 @@ int main(int argc, char *argv[])
{ "kind", 1, 0, 'k' },
{ 0, 0, 0, 0 }
};
-
+
c = getopt_long(argc, argv, "rhvd:p:i:k:", long_opts, &optidx);
if (c == -1)
break;
@@ -172,7 +176,7 @@ int main(int argc, char *argv[])
case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break;
case 'k': nl_cli_tc_parse_kind(tc, optarg); break;
}
- }
+ }
if (recursive)
nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(qdisc), list_qdisc, NULL);
diff --git a/src/nl-route-add.c b/src/nl-route-add.c
index d4aa767e..ed2c4e29 100644
--- a/src/nl-route-add.c
+++ b/src/nl-route-add.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-route-add.c Route addition utility
*
@@ -13,6 +14,8 @@
#include <netlink/cli/route.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static int quiet = 0;
static struct nl_cache *link_cache, *route_cache;
diff --git a/src/nl-route-delete.c b/src/nl-route-delete.c
index 884fd7fc..750b57f4 100644
--- a/src/nl-route-delete.c
+++ b/src/nl-route-delete.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-route-delete.c Delete Routes
*
@@ -13,6 +14,8 @@
#include <netlink/cli/route.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static int interactive = 0, default_yes = 0, quiet = 0;
static int deleted = 0;
static struct nl_sock *sock;
diff --git a/src/nl-route-get.c b/src/nl-route-get.c
index 9d9a4484..564fc166 100644
--- a/src/nl-route-get.c
+++ b/src/nl-route-get.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-route-get.c Get Route Attributes
*
@@ -13,6 +14,8 @@
#include <netlink/cli/route.h>
#include <netlink/cli/link.h>
+#include <linux/rtnetlink.h>
+
static void print_usage(void)
{
printf("Usage: nl-route-get <addr>\n");
@@ -43,7 +46,6 @@ static int cb(struct nl_msg *msg, void *arg)
int main(int argc, char *argv[])
{
struct nl_sock *sock;
- struct nl_cache *link_cache, *route_cache;
struct nl_addr *dst;
int err = 1;
@@ -52,8 +54,8 @@ int main(int argc, char *argv[])
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
- link_cache = nl_cli_link_alloc_cache(sock);
- route_cache = nl_cli_route_alloc_cache(sock, 0);
+ nl_cli_link_alloc_cache(sock);
+ nl_cli_route_alloc_cache(sock, 0);
dst = nl_cli_addr_parse(argv[1], AF_INET);
@@ -83,7 +85,5 @@ int main(int argc, char *argv[])
nl_cli_fatal(err, "%s", nl_geterror(err));
}
- //nl_cache_dump(route_cache, &params);
-
return 0;
}
diff --git a/src/nl-route-list.c b/src/nl-route-list.c
index e0e57be2..b6c4270c 100644
--- a/src/nl-route-list.c
+++ b/src/nl-route-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-route-list.c List route attributes
*
@@ -13,6 +14,8 @@
#include <netlink/cli/route.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static void print_usage(void)
{
printf(
diff --git a/src/nl-rule-list.c b/src/nl-rule-list.c
index 8b474fa3..b923184f 100644
--- a/src/nl-rule-list.c
+++ b/src/nl-rule-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-rule-dump.c Dump rule attributes
*
@@ -13,6 +14,8 @@
#include <netlink/cli/rule.h>
#include <netlink/cli/link.h>
+#include <linux/netlink.h>
+
static void print_usage(void)
{
printf(
@@ -34,7 +37,7 @@ int main(int argc, char *argv[])
{
struct nl_sock *sock;
struct rtnl_rule *rule;
- struct nl_cache *link_cache, *rule_cache;
+ struct nl_cache *rule_cache;
struct nl_dump_params params = {
.dp_fd = stdout,
.dp_type = NL_DUMP_LINE,
@@ -42,7 +45,7 @@ int main(int argc, char *argv[])
sock = nl_cli_alloc_socket();
nl_cli_connect(sock, NETLINK_ROUTE);
- link_cache = nl_cli_link_alloc_cache(sock);
+ nl_cli_link_alloc_cache(sock);
rule_cache = nl_cli_rule_alloc_cache(sock);
rule = nl_cli_rule_alloc();
diff --git a/src/nl-tctree-list.c b/src/nl-tctree-list.c
index d90cb28f..9e03038f 100644
--- a/src/nl-tctree-list.c
+++ b/src/nl-tctree-list.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-tctree-list.c List Traffic Control Tree
*
@@ -13,6 +14,8 @@
#include <netlink/cli/link.h>
#include <netlink/cli/qdisc.h>
#include <netlink/cli/class.h>
+
+#include <linux/netlink.h>
#include <linux/pkt_sched.h>
static struct nl_sock *sock;
@@ -50,9 +53,9 @@ static void print_class(struct nl_object *obj, void *arg)
leaf = rtnl_class_leaf_qdisc(class, qdisc_cache);
if (leaf)
- print_qdisc((struct nl_object *) leaf, arg + 2);
+ print_qdisc((struct nl_object *) leaf, (char *) arg + 2);
- print_tc_childs(TC_CAST(class), arg + 2);
+ print_tc_childs(TC_CAST(class), (char *) arg + 2);
if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
return;
@@ -85,7 +88,7 @@ static void print_qdisc(struct nl_object *obj, void *arg)
params.dp_prefix = (int)(long) arg;
nl_object_dump(obj, &params);
- print_tc_childs(TC_CAST(qdisc), arg + 2);
+ print_tc_childs(TC_CAST(qdisc), (char *) arg + 2);
if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
return;
diff --git a/src/nl-util-addr.c b/src/nl-util-addr.c
index 5f0738d5..6a811661 100644
--- a/src/nl-util-addr.c
+++ b/src/nl-util-addr.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1-only */
/*
* src/nl-util-addr.c Address Helper
*
diff --git a/tests/.gitignore b/tests/.gitignore
index 6b77cacc..90af67ad 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -7,16 +7,26 @@
/test-complex-HTB-with-hash-filters
/test-create-bond
/test-create-bridge
+/test-create-geneve
+/test-create-ifb
/test-create-ip6tnl
/test-create-ipgre
+/test-create-ipgretap
/test-create-ipip
+/test-create-ipvlan
/test-create-ipvti
+/test-create-macsec
+/test-create-macvlan
+/test-create-macvtap
/test-create-sit
/test-create-veth
/test-create-vlan
+/test-create-vrf
/test-create-vxlan
+/test-create-xfrmi
/test-delete-link
/test-genl
+/test-loopback-up-down
/test-nf-cache-mngr
/test-socket-creation
/test-suite.log
diff --git a/tests/Makefile.am b/tests/Makefile.am
deleted file mode 100644
index c388d0b5..00000000
--- a/tests/Makefile.am
+++ /dev/null
@@ -1,67 +0,0 @@
-# -*- Makefile -*-
-
-EXTRA_DIST = \
- util.h
-
-if ENABLE_UNIT_TESTS
-
-AM_CPPFLAGS = -Wall -I${top_srcdir}/include/linux-private -I${top_srcdir}/include -I${top_builddir}/include -D_GNU_SOURCE -DSYSCONFDIR=\"$(sysconfdir)/libnl\"
-
-LDADD = \
- ${top_builddir}/lib/libnl-3.la \
- ${top_builddir}/lib/libnl-nf-3.la \
- ${top_builddir}/lib/libnl-genl-3.la \
- ${top_builddir}/lib/libnl-route-3.la \
- @CHECK_LIBS@
-
-AM_CFLAGS = @CHECK_CFLAGS@
-
-UNIT_TESTS = check-all
-
-check_PROGRAMS = \
- test-create-bond \
- test-create-vlan \
- test-create-vxlan \
- test-create-veth \
- test-create-bridge \
- test-create-ip6tnl \
- test-create-ipgre \
- test-create-ipip \
- test-create-ipvti \
- test-create-sit \
- test-delete-link \
- test-socket-creation \
- test-complex-HTB-with-hash-filters \
- test-u32-filter-with-actions \
- ${UNIT_TESTS}
-
-TESTS = \
- ${UNIT_TESTS}
-
-if ENABLE_CLI
-LDADD += ${top_builddir}/src/lib/libnl-cli-3.la
-check_PROGRAMS += \
- test-cache-mngr \
- test-genl \
- test-nf-cache-mngr
-endif
-
-test_cache_mngr_SOURCES = test-cache-mngr.c
-test_create_bond_SOURCES = test-create-bond.c
-test_create_vlan_SOURCES = test-create-vlan.c
-test_create_vxlan_SOURCES = test-create-vxlan.c
-test_create_veth_SOURCES = test-create-veth.c
-test_create_bridge_SOURCES = test-create-bridge.c
-test_delete_link_SOURCES = test-delete-link.c
-test_genl_SOURCES = test-genl.c
-test_nf_cache_mngr_SOURCES = test-nf-cache-mngr.c
-test_socket_creation_SOURCES = test-socket-creation.c
-test_complex_HTB_with_hash_filters_SOURCES = test-complex-HTB-with-hash-filters.c
-test_u32_filter_with_actions_SOURCES = test-u32-filter-with-actions.c
-
-# Unit tests
-check_all_SOURCES = \
- check-all.c \
- check-addr.c \
- check-attr.c
-endif
diff --git a/tests/check-addr.c b/tests/check-addr.c
index 39f3ede4..48a2d931 100644
--- a/tests/check-addr.c
+++ b/tests/check-addr.c
@@ -12,6 +12,8 @@
#include <check.h>
#include <netlink/addr.h>
+#include "util.h"
+
START_TEST(addr_alloc)
{
struct nl_addr *addr;
diff --git a/tests/check-all.c b/tests/check-all.c
index e4318024..7b738daa 100644
--- a/tests/check-all.c
+++ b/tests/check-all.c
@@ -11,8 +11,7 @@
#include <check.h>
-extern Suite *make_nl_addr_suite(void);
-extern Suite *make_nl_attr_suite(void);
+#include "util.h"
static Suite *main_suite(void)
{
@@ -32,6 +31,7 @@ int main(int argc, char *argv[])
srunner_add_suite(runner, make_nl_addr_suite());
srunner_add_suite(runner, make_nl_attr_suite());
+ srunner_add_suite(runner, make_nl_ematch_tree_clone_suite());
/* Do not add testsuites below this line */
diff --git a/tests/check-attr.c b/tests/check-attr.c
index d8622301..0390997c 100644
--- a/tests/check-attr.c
+++ b/tests/check-attr.c
@@ -13,6 +13,8 @@
#include <netlink/attr.h>
#include <netlink/msg.h>
+#include <linux/netlink.h>
+
START_TEST(attr_size)
{
fail_if(nla_attr_size(0) != NLA_HDRLEN,
diff --git a/tests/check-ematch-tree-clone.c b/tests/check-ematch-tree-clone.c
new file mode 100644
index 00000000..9c35c52e
--- /dev/null
+++ b/tests/check-ematch-tree-clone.c
@@ -0,0 +1,143 @@
+#include <netlink-private/types.h>
+#include <netlink/route/cls/ematch.h>
+
+#include <linux/netlink.h>
+
+#include <stdio.h>
+#include <time.h>
+
+#include <check.h>
+#include "util.h"
+
+#define MAX_DEPTH 6
+#define MAX_CHILDREN 5
+
+static int current_depth = 0;
+static int id = 1;
+static long long array_size = 0;
+
+static int *src_result = NULL, *dst_result = NULL;
+
+static long long my_pow(long long x, long long y)
+{
+ int ret = x;
+
+ if (y == 0)
+ return 1;
+
+ if (y < 0 || x == 0)
+ return 0;
+
+ while(--y) {
+ ret *= x;
+ }
+
+ return ret;
+}
+
+static long int generate_random(long int max)
+{
+ srandom(time(NULL) + id);
+ return (random() % max);
+}
+
+static int build_children(struct nl_list_head *parent)
+{
+ int i, num = 0;
+ struct rtnl_ematch *child = NULL;
+
+ if (!parent)
+ return 0;
+
+ if (++current_depth > MAX_DEPTH) {
+ --current_depth;
+ return 0;
+ }
+
+ num = generate_random(MAX_CHILDREN + 1);
+ for (i = 0; i < num; ++i) {
+ child = rtnl_ematch_alloc();
+ if (!child) {
+ printf("Mem alloc error\n");
+ exit(1);
+ }
+ build_children(&child->e_childs);
+ child->e_id = id++;
+ nl_list_add_tail(&child->e_list, parent);
+ }
+
+ --current_depth;
+ return 0;
+}
+
+static void build_src_cgroup(struct rtnl_ematch_tree *tree)
+{
+ build_children(&tree->et_list);
+}
+
+static void dump_ematch_list(struct nl_list_head *head, int *result, int *index)
+{
+ struct rtnl_ematch *pos = NULL;
+
+ nl_list_for_each_entry(pos, head, e_list) {
+ if (!nl_list_empty(&pos->e_childs))
+ dump_ematch_list(&pos->e_childs, result, index);
+ result[*index] = pos->e_id;
+ (*index)++;
+ }
+}
+
+static void dump_ematch_tree(struct rtnl_ematch_tree *tree, int *result, int *index)
+{
+ if (!tree)
+ return;
+
+ dump_ematch_list(&tree->et_list, result, index);
+}
+
+static int compare(int *r1, int *r2, int len)
+{
+ int i = 0;
+ for (i = 0; i < len; ++i) {
+ if (r1[i] != r2[i])
+ return -1;
+ }
+ return 0;
+}
+
+START_TEST(ematch_tree_clone)
+{
+ struct rtnl_ematch_tree *src = NULL, *dst = NULL;
+ int i = 0, j = 0;
+
+ array_size = (MAX_DEPTH * my_pow(MAX_CHILDREN, MAX_DEPTH)) / 2;
+ src_result = calloc(4, array_size);
+ dst_result = calloc(4, array_size);
+
+ src = rtnl_ematch_tree_alloc(2);
+
+ build_src_cgroup(src);
+ dump_ematch_tree(src, src_result, &i);
+
+ dst = rtnl_ematch_tree_clone(src);
+ dump_ematch_tree(dst, dst_result, &j);
+
+ fail_if(!dst);
+ fail_if(i != j);
+ fail_if(compare(src_result, dst_result, i));
+
+ free(src_result);
+ free(dst_result);
+}
+END_TEST
+
+Suite *make_nl_ematch_tree_clone_suite(void)
+{
+ Suite *suite = suite_create("Clone ematch tree");
+
+ TCase *ematch_tree = tcase_create("Core");
+ tcase_add_test(ematch_tree, ematch_tree_clone);
+ suite_add_tcase(suite, ematch_tree);
+
+ return suite;
+}
diff --git a/tests/test-cache-mngr.c b/tests/test-cache-mngr.c
index 8999e587..97614520 100644
--- a/tests/test-cache-mngr.c
+++ b/tests/test-cache-mngr.c
@@ -5,6 +5,8 @@
#include <netlink-private/cache-api.h>
+#include <linux/netlink.h>
+
static int quit = 0;
static struct nl_dump_params dp = {
diff --git a/tests/test-complex-HTB-with-hash-filters.c b/tests/test-complex-HTB-with-hash-filters.c
index 48cf5e32..b1bf36e5 100644
--- a/tests/test-complex-HTB-with-hash-filters.c
+++ b/tests/test-complex-HTB-with-hash-filters.c
@@ -18,6 +18,7 @@
#include <netlink/route/classifier.h>
#include <netlink/route/class.h>
#include <linux/if_ether.h>
+#include <linux/pkt_cls.h>
#include <netlink/attr.h>
//#include "include/rtnl_u32.h"
@@ -26,10 +27,12 @@
#include <string.h>
//#include "include/rtnl_u32_addon.h"
+#include <linux/netlink.h>
+
#define TC_HANDLE(maj, min) (TC_H_MAJ((maj) << 16) | TC_H_MIN(min))
/* some functions are copied from iproute-tc tool */
-int get_u32(__u32 *val, const char *arg, int base)
+static int get_u32(__u32 *val, const char *arg, int base)
{
unsigned long res;
char *ptr;
@@ -43,7 +46,7 @@ int get_u32(__u32 *val, const char *arg, int base)
return 0;
}
-int get_u32_handle(__u32 *handle, const char *str)
+static int get_u32_handle(__u32 *handle, const char *str)
{
__u32 htid=0, hash=0, nodeid=0;
char *tmp = strchr(str, ':');
@@ -78,7 +81,7 @@ int get_u32_handle(__u32 *handle, const char *str)
return 0;
}
-uint32_t get_u32_parse_handle(const char *cHandle)
+static uint32_t get_u32_parse_handle(const char *cHandle)
{
uint32_t handle=0;
@@ -94,7 +97,7 @@ uint32_t get_u32_parse_handle(const char *cHandle)
return handle;
}
-int get_tc_classid(__u32 *h, const char *str)
+static int get_tc_classid(__u32 *h, const char *str)
{
__u32 maj, min;
char *p;
@@ -134,7 +137,7 @@ ok:
* Function that adds a new filter and attach it to a hash table
*
*/
-int u32_add_filter_on_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio,
+static int u32_add_filter_on_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio,
uint32_t keyval, uint32_t keymask, int keyoff, int keyoffmask,
uint32_t htid, uint32_t classid
)
@@ -186,7 +189,7 @@ int u32_add_filter_on_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint3
* and set next hash table link with hash mask
*
*/
-int u32_add_filter_on_ht_with_hashmask(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio,
+static int u32_add_filter_on_ht_with_hashmask(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio,
uint32_t keyval, uint32_t keymask, int keyoff, int keyoffmask,
uint32_t htid, uint32_t htlink, uint32_t hmask, uint32_t hoffset
)
@@ -237,7 +240,7 @@ int u32_add_filter_on_ht_with_hashmask(struct nl_sock *sock, struct rtnl_link *r
/*
* function that creates a new hash table
*/
-int u32_add_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio, uint32_t htid, uint32_t divisor)
+static int u32_add_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio, uint32_t htid, uint32_t divisor)
{
int err;
@@ -276,7 +279,7 @@ int u32_add_ht(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio,
/*
* function that adds a new HTB qdisc and set the default class for unclassified traffic
*/
-int qdisc_add_HTB(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t defaultClass)
+static int qdisc_add_HTB(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t defaultClass)
{
struct rtnl_qdisc *qdisc;
@@ -326,7 +329,7 @@ int qdisc_add_HTB(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t def
/*
* function that adds a new HTB class and set its parameters
*/
-int class_add_HTB(struct nl_sock *sock, struct rtnl_link *rtnlLink,
+static int class_add_HTB(struct nl_sock *sock, struct rtnl_link *rtnlLink,
uint32_t parentMaj, uint32_t parentMin,
uint32_t childMaj, uint32_t childMin,
uint64_t rate, uint64_t ceil,
@@ -388,7 +391,7 @@ int class_add_HTB(struct nl_sock *sock, struct rtnl_link *rtnlLink,
/*
* function that adds a HTB root class and set its parameters
*/
-int class_add_HTB_root(struct nl_sock *sock, struct rtnl_link *rtnlLink,
+static int class_add_HTB_root(struct nl_sock *sock, struct rtnl_link *rtnlLink,
uint64_t rate, uint64_t ceil,
uint32_t burst, uint32_t cburst
)
@@ -443,7 +446,7 @@ int class_add_HTB_root(struct nl_sock *sock, struct rtnl_link *rtnlLink,
/*
* function that adds a new SFQ qdisc as a leaf for a HTB class
*/
-int qdisc_add_SFQ_leaf(struct nl_sock *sock, struct rtnl_link *rtnlLink,
+static int qdisc_add_SFQ_leaf(struct nl_sock *sock, struct rtnl_link *rtnlLink,
uint32_t parentMaj, uint32_t parentMin,
int quantum, int limit, int perturb
)
@@ -514,6 +517,8 @@ int main() {
struct nl_cache *link_cache;
+ uint32_t i;
+
if (!(sock = nl_socket_alloc())) {
printf("Unable to allocate netlink socket\n");
exit(1);
@@ -576,7 +581,6 @@ int main() {
* each entry in hash table match a byte from IP address specified later by a hash key
*/
- uint32_t i;
for (i = 1; i <= 0xf; i++)
u32_add_ht(sock, link, 1, i, 256);
diff --git a/tests/test-create-bond.c b/tests/test-create-bond.c
index 11bc5b09..326e0ef7 100644
--- a/tests/test-create-bond.c
+++ b/tests/test-create-bond.c
@@ -2,6 +2,8 @@
#include <netlink/route/link.h>
#include <netlink/route/link/bonding.h>
+#include <linux/netlink.h>
+
int main(int argc, char *argv[])
{
struct rtnl_link *link;
diff --git a/tests/test-create-bridge.c b/tests/test-create-bridge.c
index 7202cd7e..a9d9f2e0 100644
--- a/tests/test-create-bridge.c
+++ b/tests/test-create-bridge.c
@@ -2,10 +2,12 @@
#include <netlink/route/link.h>
#include <netlink/route/link/bridge.h>
+#include <linux/netlink.h>
+
#define TEST_BRIDGE_NAME "testbridge"
#define TEST_INTERFACE_NAME "testtap1"
-int create_bridge(struct nl_sock *sk, struct nl_cache *link_cache, const char *name) {
+static int create_bridge(struct nl_sock *sk, struct nl_cache *link_cache, const char *name) {
struct rtnl_link *link;
int err;
@@ -29,6 +31,7 @@ int main(int argc, char *argv[])
struct rtnl_link *link;
struct nl_cache *link_cache;
struct nl_sock *sk;
+ struct rtnl_link *ltap;
int err;
sk = nl_socket_alloc();
@@ -50,7 +53,7 @@ int main(int argc, char *argv[])
nl_cache_refill(sk, link_cache);
link = rtnl_link_get_by_name(link_cache, TEST_BRIDGE_NAME);
- struct rtnl_link *ltap = rtnl_link_get_by_name(link_cache, TEST_INTERFACE_NAME);
+ ltap = rtnl_link_get_by_name(link_cache, TEST_INTERFACE_NAME);
if (!ltap) {
fprintf(stderr, "You should create a tap interface before lunch this test (# tunctl -t %s)\n", TEST_INTERFACE_NAME);
return -1;
@@ -65,6 +68,11 @@ int main(int argc, char *argv[])
fprintf(stderr, "Link is not a bridge\n");
return -2;
}
+
+ rtnl_link_put(ltap);
+ nl_cache_refill(sk, link_cache);
+ ltap = rtnl_link_get_by_name(link_cache, TEST_INTERFACE_NAME);
+
if(rtnl_link_get_master(ltap) <= 0) {
fprintf(stderr, "Interface is not attached to a bridge\n");
return -3;
diff --git a/tests/test-create-geneve.c b/tests/test-create-geneve.c
new file mode 100644
index 00000000..37b220ad
--- /dev/null
+++ b/tests/test-create-geneve.c
@@ -0,0 +1,87 @@
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/geneve.h>
+
+#include <linux/netlink.h>
+
+#define IPv6 1
+
+int main(int argc, char *argv[])
+{
+ struct rtnl_link *link;
+ struct nl_addr *addr;
+ struct nl_sock *sk;
+ int err;
+
+ sk = nl_socket_alloc();
+ if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+ nl_perror(err, "Unable to connect socket");
+ return err;
+ }
+
+ link = rtnl_link_geneve_alloc();
+
+ rtnl_link_set_name(link, "gnv123");
+
+ if ((err = rtnl_link_geneve_set_id(link, 123)) < 0) {
+ nl_perror(err, "Unable to set GENEVE ID");
+ return err;
+ }
+
+#if IPv6
+ if ((err = nl_addr_parse("2001:0db8:0:f101::1/64", AF_INET6, &addr)) < 0) {
+ nl_perror(err, "Unable to parse IPv6 address");
+ return err;
+ }
+ if ((err = rtnl_link_geneve_set_label(link, 123)) < 0) {
+ nl_perror(err, "Unable to set label");
+ return err;
+ }
+
+ if ((err = rtnl_link_geneve_set_udp_zero_csum6_tx(link, 1)) < 0) {
+ nl_perror(err, "Unable to set skip transmitted UDP checksum");
+ return err;
+ }
+
+ if ((err = rtnl_link_geneve_set_udp_zero_csum6_rx(link, 1)) < 0) {
+ nl_perror(err, "Unable to set skip received UDP checksum");
+ return err;
+ }
+#else
+ if ((err = nl_addr_parse("10.4.4.4", AF_INET, &addr)) < 0) {
+ nl_perror(err, "Unable to parse IP address");
+ return err;
+ }
+#endif
+
+ if ((err = rtnl_link_geneve_set_remote(link, addr)) < 0) {
+ nl_perror(err, "Unable to set remote address");
+ return err;
+ }
+ nl_addr_put(addr);
+
+ if ((err = rtnl_link_geneve_set_ttl(link, 1)) < 0) {
+ nl_perror(err, "Unable to set TTL");
+ return err;
+ }
+
+ if ((err = rtnl_link_geneve_set_tos(link, 0)) < 0) {
+ nl_perror(err, "Unable to set ToS");
+ return err;
+ }
+
+ if ((err = rtnl_link_geneve_set_port(link, 5060)) < 0) {
+ nl_perror(err, "Unable to set port");
+ return err;
+ }
+
+ if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
+ nl_perror(err, "Unable to add link");
+ return err;
+ }
+
+ rtnl_link_put(link);
+ nl_close(sk);
+
+ return 0;
+}
diff --git a/tests/test-create-ifb.c b/tests/test-create-ifb.c
new file mode 100644
index 00000000..d154ffdc
--- /dev/null
+++ b/tests/test-create-ifb.c
@@ -0,0 +1,31 @@
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#include <linux/netlink.h>
+
+int main(int argc, char *argv[])
+{
+ struct rtnl_link *link;
+ struct nl_sock *sk;
+ int err;
+
+ sk = nl_socket_alloc();
+ if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+ nl_perror(err, "Unable to connect socket");
+ return err;
+ }
+
+ link = rtnl_link_alloc();
+ rtnl_link_set_type(link, "ifb");
+ rtnl_link_set_name(link, "ifb1");
+
+ if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
+ nl_perror(err, "Unable to add link");
+ return err;
+ }
+
+ rtnl_link_put(link);
+ nl_close(sk);
+
+ return 0;
+}
diff --git a/tests/test-create-ipgretap.c b/tests/test-create-ipgretap.c
new file mode 100644
index 00000000..1fe82313
--- /dev/null
+++ b/tests/test-create-ipgretap.c
@@ -0,0 +1,56 @@
+#include <netlink/route/link/ipgre.h>
+#include <netlink-private/netlink.h>
+
+int main(int argc, char *argv[])
+{
+ struct nl_cache *link_cache;
+ struct rtnl_link *link;
+ struct in_addr addr;
+ struct nl_sock *sk;
+ int err, if_index;
+
+ sk = nl_socket_alloc();
+ if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+ nl_perror(err, "Unable to connect socket");
+ return err;
+ }
+
+ err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache);
+ if ( err < 0) {
+ nl_perror(err, "Unable to allocate cache");
+ return err;
+ }
+
+ if_index = rtnl_link_name2i(link_cache, "enp0s5");
+ if (!if_index) {
+ fprintf(stderr, "Unable to lookup enp0s5");
+ return -1;
+ }
+
+ link = rtnl_link_ipgretap_alloc();
+ if(!link) {
+ nl_perror(err, "Unable to allocate link");
+ return -1;
+
+ }
+ rtnl_link_set_name(link, "ipgre-tap");
+ rtnl_link_ipgre_set_link(link, if_index);
+
+ inet_pton(AF_INET, "10.211.55.10", &addr.s_addr);
+ rtnl_link_ipgre_set_local(link, addr.s_addr);
+
+ inet_pton(AF_INET, "10.133.6.33", &addr.s_addr);
+ rtnl_link_ipgre_set_remote(link, addr.s_addr);
+
+ rtnl_link_ipgre_set_ttl(link, 64);
+ err = rtnl_link_add(sk, link, NLM_F_CREATE);
+ if (err < 0) {
+ nl_perror(err, "Unable to add link");
+ return err;
+ }
+
+ rtnl_link_put(link);
+ nl_close(sk);
+
+ return 0;
+}
diff --git a/tests/test-create-ipvlan.c b/tests/test-create-ipvlan.c
new file mode 100644
index 00000000..50bac541
--- /dev/null
+++ b/tests/test-create-ipvlan.c
@@ -0,0 +1,47 @@
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/ipvlan.h>
+
+#include <linux/netlink.h>
+
+int main(int argc, char *argv[])
+{
+ struct rtnl_link *link;
+ struct nl_cache *link_cache;
+ struct nl_sock *sk;
+ int err, master_index;
+
+ sk = nl_socket_alloc();
+ if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+ nl_perror(err, "Unable to connect socket");
+ return err;
+ }
+
+ if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache)) < 0) {
+ nl_perror(err, "Unable to allocate cache");
+ return err;
+ }
+
+ if (!(master_index = rtnl_link_name2i(link_cache, "eth0"))) {
+ fprintf(stderr, "Unable to lookup eth0");
+ return -1;
+ }
+
+ if (!(link = rtnl_link_ipvlan_alloc())) {
+ fprintf(stderr, "Unable to allocate link");
+ return -1;
+ }
+
+ rtnl_link_set_link(link, master_index);
+ rtnl_link_ipvlan_set_mode(link, rtnl_link_ipvlan_str2mode("l2"));
+
+ if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
+ nl_perror(err, "Unable to add link");
+ return err;
+ }
+
+ rtnl_link_put(link);
+ nl_close(sk);
+
+ return 0;
+}
diff --git a/tests/test-create-macsec.c b/tests/test-create-macsec.c
new file mode 100644
index 00000000..efadf6b5
--- /dev/null
+++ b/tests/test-create-macsec.c
@@ -0,0 +1,51 @@
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#include <linux/netlink.h>
+#include <linux/if_link.h>
+
+#include <netlink/route/link/macsec.h>
+
+int main(int argc, char *argv[])
+{
+ struct rtnl_link *link;
+ struct nl_cache *link_cache;
+ struct nl_sock *sk;
+ int err, master_index;
+
+ sk = nl_socket_alloc();
+ if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+ nl_perror(err, "Unable to connect socket");
+ return err;
+ }
+
+ if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache)) < 0) {
+ nl_perror(err, "Unable to allocate cache");
+ return err;
+ }
+
+ if (!(master_index = rtnl_link_name2i(link_cache, "eth0"))) {
+ fprintf(stderr, "Unable to lookup eth0");
+ return -1;
+ }
+
+
+ link = rtnl_link_macsec_alloc();
+
+ rtnl_link_set_link(link, master_index);
+
+ rtnl_link_macsec_set_port(link, 10);
+ rtnl_link_macsec_set_encrypt(link, 1);
+ rtnl_link_macsec_set_replay_protect(link, 1);
+ rtnl_link_macsec_set_window(link, 200);
+
+ if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
+ nl_perror(err, "Unable to add link");
+ return err;
+ }
+
+ rtnl_link_put(link);
+ nl_close(sk);
+
+ return 0;
+}
diff --git a/tests/test-create-macvlan.c b/tests/test-create-macvlan.c
index 64779237..f520b674 100644
--- a/tests/test-create-macvlan.c
+++ b/tests/test-create-macvlan.c
@@ -1,7 +1,11 @@
+#include <netinet/ether.h>
+
#include <netlink/netlink.h>
#include <netlink/route/link.h>
#include <netlink/route/link/macvlan.h>
+#include <linux/netlink.h>
+
int main(int argc, char *argv[])
{
struct rtnl_link *link;
diff --git a/tests/test-create-macvtap.c b/tests/test-create-macvtap.c
new file mode 100644
index 00000000..27d1969d
--- /dev/null
+++ b/tests/test-create-macvtap.c
@@ -0,0 +1,52 @@
+#include <netinet/ether.h>
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/macvtap.h>
+
+#include <linux/netlink.h>
+
+int main(int argc, char *argv[])
+{
+ struct rtnl_link *link;
+ struct nl_cache *link_cache;
+ struct nl_sock *sk;
+ struct nl_addr* addr;
+ int err, master_index;
+
+ sk = nl_socket_alloc();
+ if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+ nl_perror(err, "Unable to connect socket");
+ return err;
+ }
+
+ if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache)) < 0) {
+ nl_perror(err, "Unable to allocate cache");
+ return err;
+ }
+
+ if (!(master_index = rtnl_link_name2i(link_cache, "eth0"))) {
+ fprintf(stderr, "Unable to lookup eth0");
+ return -1;
+ }
+
+ link = rtnl_link_macvtap_alloc();
+
+ rtnl_link_set_link(link, master_index);
+
+ addr = nl_addr_build(AF_LLC, ether_aton("00:11:22:33:44:55"), ETH_ALEN);
+ rtnl_link_set_addr(link, addr);
+ nl_addr_put(addr);
+
+ rtnl_link_macvtap_set_mode(link, rtnl_link_macvtap_str2mode("bridge"));
+
+ if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
+ nl_perror(err, "Unable to add link");
+ return err;
+ }
+
+ rtnl_link_put(link);
+ nl_close(sk);
+
+ return 0;
+}
diff --git a/tests/test-create-veth.c b/tests/test-create-veth.c
index db5ab8b1..9600f8dd 100644
--- a/tests/test-create-veth.c
+++ b/tests/test-create-veth.c
@@ -2,6 +2,8 @@
#include <netlink/route/link.h>
#include <netlink/route/link/veth.h>
+#include <linux/netlink.h>
+
int main(int argc, char *argv[])
{
struct rtnl_link *link;
diff --git a/tests/test-create-vlan.c b/tests/test-create-vlan.c
index 64e478f4..04756d4a 100644
--- a/tests/test-create-vlan.c
+++ b/tests/test-create-vlan.c
@@ -2,6 +2,8 @@
#include <netlink/route/link.h>
#include <netlink/route/link/vlan.h>
+#include <linux/netlink.h>
+
int main(int argc, char *argv[])
{
struct rtnl_link *link;
diff --git a/tests/test-create-vrf.c b/tests/test-create-vrf.c
new file mode 100644
index 00000000..c3d23e7f
--- /dev/null
+++ b/tests/test-create-vrf.c
@@ -0,0 +1,61 @@
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/vrf.h>
+
+#include <linux/netlink.h>
+
+int main(int argc, char *argv[])
+{
+ struct nl_cache *link_cache;
+ struct rtnl_link *link, *link2;
+ struct nl_sock *sk;
+ uint32_t tb_id;
+ int err;
+
+ sk = nl_socket_alloc();
+ if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+ nl_perror(err, "Unable to connect socket");
+ return err;
+ }
+
+ if (!(link = rtnl_link_vrf_alloc())) {
+ fprintf(stderr, "Unable to allocate link");
+ return -1;
+ }
+
+ rtnl_link_set_name(link, "vrf-red");
+
+ if ((err = rtnl_link_vrf_set_tableid(link, 10)) < 0) {
+ nl_perror(err, "Unable to set VRF table id");
+ return err;
+ }
+
+ if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) {
+ nl_perror(err, "Unable to add link");
+ return err;
+ }
+
+ if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache)) < 0) {
+ nl_perror(err, "Unable to allocate cache");
+ return err;
+ }
+
+ if (!(link2 = rtnl_link_get_by_name(link_cache, "vrf-red"))) {
+ fprintf(stderr, "Unable to lookup vrf-red");
+ return -1;
+ }
+
+ if ((err = rtnl_link_vrf_get_tableid(link2, &tb_id)) < 0) {
+ nl_perror(err, "Unable to get VRF table id");
+ return err;
+ }
+
+ if (tb_id != 10) {
+ fprintf(stderr, "Mismatch with VRF table id\n");
+ }
+
+ rtnl_link_put(link);
+ nl_close(sk);
+
+ return 0;
+}
diff --git a/tests/test-create-vxlan.c b/tests/test-create-vxlan.c
index 98a5103c..855fdb5d 100644
--- a/tests/test-create-vxlan.c
+++ b/tests/test-create-vxlan.c
@@ -2,6 +2,8 @@
#include <netlink/route/link.h>
#include <netlink/route/link/vxlan.h>
+#include <linux/netlink.h>
+
int main(int argc, char *argv[])
{
struct rtnl_link *link;
diff --git a/tests/test-create-xfrmi.c b/tests/test-create-xfrmi.c
new file mode 100644
index 00000000..3a01a4ff
--- /dev/null
+++ b/tests/test-create-xfrmi.c
@@ -0,0 +1,49 @@
+#include <netlink/route/link/xfrmi.h>
+#include <netlink-private/netlink.h>
+
+int main(int argc, char *argv[])
+{
+ struct nl_cache *link_cache;
+ struct rtnl_link *link;
+ struct nl_sock *sk;
+ int err, if_index;
+
+ sk = nl_socket_alloc();
+ if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+ nl_perror(err, "Unable to connect socket");
+ return err;
+ }
+
+ err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache);
+ if (err < 0) {
+ nl_perror(err, "Unable to allocate cache");
+ return err;
+ }
+
+ if_index = rtnl_link_name2i(link_cache, "eth0");
+ if (!if_index) {
+ fprintf(stderr, "Unable to lookup eth0");
+ return -1;
+ }
+
+ link = rtnl_link_xfrmi_alloc();
+ if (!link) {
+ nl_perror(err, "Unable to allocate link");
+ return -1;
+
+ }
+
+ rtnl_link_set_name(link, "ipsec0");
+ rtnl_link_xfrmi_set_link(link, if_index);
+ rtnl_link_xfrmi_set_if_id(link, 16);
+
+ err = rtnl_link_add(sk, link, NLM_F_CREATE);
+ if (err < 0) {
+ nl_perror(err, "Unable to add link");
+ return err;
+ }
+
+ rtnl_link_put(link);
+ nl_close(sk);
+ return 0;
+}
diff --git a/tests/test-delete-link.c b/tests/test-delete-link.c
index 9cf1034e..86331239 100644
--- a/tests/test-delete-link.c
+++ b/tests/test-delete-link.c
@@ -1,6 +1,8 @@
#include <netlink/netlink.h>
#include <netlink/route/link.h>
+#include <linux/netlink.h>
+
int main(int argc, char *argv[])
{
struct rtnl_link *link;
diff --git a/tests/test-genl.c b/tests/test-genl.c
index 74aea106..42db5011 100644
--- a/tests/test-genl.c
+++ b/tests/test-genl.c
@@ -1,5 +1,7 @@
#include <netlink/cli/utils.h>
+
#include <linux/taskstats.h>
+#include <linux/genetlink.h>
static struct nla_policy attr_policy[TASKSTATS_TYPE_MAX+1] = {
[TASKSTATS_TYPE_PID] = { .type = NLA_U32 },
@@ -99,7 +101,7 @@ int main(int argc, char *argv[])
if ((err = nla_put_u32(msg, TASKSTATS_CMD_ATTR_PID, 1)) < 0)
nl_cli_fatal(err, "Unable to add attribute: %s", nl_geterror(err));
- if ((err = nl_send_auto_complete(sock, msg)) < 0)
+ if ((err = nl_send_auto(sock, msg)) < 0)
nl_cli_fatal(err, "Unable to send message: %s", nl_geterror(err));
nlmsg_free(msg);
diff --git a/tests/test-loopback-up-down.c b/tests/test-loopback-up-down.c
new file mode 100644
index 00000000..5a7bcb1a
--- /dev/null
+++ b/tests/test-loopback-up-down.c
@@ -0,0 +1,54 @@
+#include <net/if.h>
+#include <netlink/route/link.h>
+
+int main(void)
+{
+ struct nl_sock *sk;
+ struct rtnl_link *link, *change;
+ struct nl_cache *cache;
+ int err = 0;
+
+ sk = nl_socket_alloc();
+ if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) {
+ nl_perror(err, "Unable to connect socket");
+ return err;
+ }
+
+ if ((err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &cache)) < 0) {
+ nl_perror(err, "Unable to allocate cache");
+ goto out;
+ }
+
+ if (!(link = rtnl_link_get_by_name(cache, "lo"))) {
+ fprintf(stderr, "Interface not found\n");
+ err = 1;
+ goto out;
+ }
+
+ /* exit if the loopback interface is already deactivated */
+ err = rtnl_link_get_flags(link);
+ if (!(err & IFF_UP)) {
+ err = 0;
+ goto out;
+ }
+
+ change = rtnl_link_alloc();
+ rtnl_link_unset_flags(change, IFF_UP);
+
+ if ((err = rtnl_link_change(sk, link, change, 0)) < 0) {
+ nl_perror(err, "Unable to deactivate lo");
+ goto out;
+ }
+
+ rtnl_link_set_flags(change, IFF_UP);
+ if ((err = rtnl_link_change(sk, link, change, 0)) < 0) {
+ nl_perror(err, "Unable to activate lo");
+ goto out;
+ }
+
+ err = 0;
+
+out:
+ nl_socket_free(sk);
+ return err;
+}
diff --git a/tests/test-nf-cache-mngr.c b/tests/test-nf-cache-mngr.c
index b4f30223..7625e3fe 100644
--- a/tests/test-nf-cache-mngr.c
+++ b/tests/test-nf-cache-mngr.c
@@ -1,5 +1,7 @@
#include <netlink/cli/utils.h>
+#include <linux/netlink.h>
+
static void change_cb(struct nl_cache *cache, struct nl_object *obj,
int action, void *data)
{
diff --git a/tests/test-u32-filter-with-actions.c b/tests/test-u32-filter-with-actions.c
index 55f913af..e9910e33 100644
--- a/tests/test-u32-filter-with-actions.c
+++ b/tests/test-u32-filter-with-actions.c
@@ -18,13 +18,17 @@
#include <netlink/route/classifier.h>
#include <netlink/route/action.h>
#include <netlink/route/act/mirred.h>
+#include <netlink/route/act/skbedit.h>
#include <netlink/route/class.h>
-#include <linux/if_ether.h>
-
#include <netlink/attr.h>
+
#include <stdio.h>
#include <string.h>
+#include <linux/if_ether.h>
+#include <linux/tc_act/tc_mirred.h>
+#include <linux/netlink.h>
+
#define TC_HANDLE(maj, min) (TC_H_MAJ((maj) << 16) | TC_H_MIN(min))
/* some functions are copied from iproute-tc tool */
@@ -101,7 +105,7 @@ static uint32_t get_u32_parse_handle(const char *cHandle)
static
int u32_add_filter_on_ht_with_hashmask(struct nl_sock *sock, struct rtnl_link *rtnlLink, uint32_t prio,
uint32_t keyval, uint32_t keymask, int keyoff, int keyoffmask,
- uint32_t htid, uint32_t htlink, uint32_t hmask, uint32_t hoffset, struct rtnl_act *act)
+ uint32_t htid, uint32_t htlink, uint32_t hmask, uint32_t hoffset, struct rtnl_act *act, struct rtnl_act *act2)
{
struct rtnl_cls *cls;
int err;
@@ -136,6 +140,8 @@ int u32_add_filter_on_ht_with_hashmask(struct nl_sock *sock, struct rtnl_link *r
rtnl_u32_add_action(cls, act);
+ rtnl_u32_add_action(cls, act2);
+
if ((err = rtnl_cls_add(sock, cls, NLM_F_CREATE))) {
printf("Can not add classifier: %s\n", nl_geterror(err));
@@ -236,7 +242,8 @@ int main(void)
char chashlink[16]="";
int err;
struct nl_cache *link_cache;
- struct rtnl_act *act;
+ struct rtnl_act *act, *act2;
+ uint32_t i;
if (!(sock = nl_socket_alloc())) {
printf("Unable to allocate netlink socket\n");
@@ -284,7 +291,6 @@ int main(void)
* each entry in hash table match a byte from IP address specified later by a hash key
*/
- uint32_t i;
for (i = 1; i <= 0xf; i++)
u32_add_ht(sock, link, 1, i, 256);
@@ -354,7 +360,7 @@ int main(void)
u32_add_filter_on_ht_with_hashmask(sock, link, 1,
0x0, 0x0, direction, 0,
- 0, htlink, 0xff000000, direction, NULL);
+ 0, htlink, 0xff000000, direction, NULL, NULL);
/*
* For each first byte that we need to match we will create a new hash table
@@ -373,16 +379,24 @@ int main(void)
* previous steps.
*
*/
-
act = rtnl_act_alloc();
if (!act) {
printf("rtnl_act_alloc() returns %p\n", act);
return -1;
- }
- rtnl_tc_set_kind(TC_CAST(act), "mirred");
- rtnl_mirred_set_action(act, TCA_EGRESS_REDIR);
- rtnl_mirred_set_policy(act, TC_ACT_STOLEN);
- rtnl_mirred_set_ifindex(act, rtnl_link_name2i(link_cache, "eth1"));
+ }
+ rtnl_tc_set_kind(TC_CAST(act), "skbedit");
+ rtnl_skbedit_set_queue_mapping(act, 4);
+ rtnl_skbedit_set_action(act, TC_ACT_PIPE);
+
+ act2 = rtnl_act_alloc();
+ if (!act2) {
+ printf("rtnl_act_alloc() returns %p\n", act2);
+ return -1;
+ }
+ rtnl_tc_set_kind(TC_CAST(act2), "mirred");
+ rtnl_mirred_set_action(act2, TCA_EGRESS_REDIR);
+ rtnl_mirred_set_policy(act2, TC_ACT_STOLEN);
+ rtnl_mirred_set_ifindex(act2, rtnl_link_name2i(link_cache, "eth1"));
// /8 check
// 10.0.0.0/8
@@ -392,7 +406,7 @@ int main(void)
u32_add_filter_on_ht_with_hashmask(sock, link, 1,
0x0a000000, 0xff000000, direction, 0,
- htid, htlink, 0x00ff0000, direction, act);
+ htid, htlink, 0x00ff0000, direction, act, act2);
rtnl_act_put(act);
nl_socket_free(sock);
diff --git a/tests/util.h b/tests/util.h
index c6753835..8c9acf12 100644
--- a/tests/util.h
+++ b/tests/util.h
@@ -3,3 +3,8 @@
#define nl_fail_if(condition, error, message) \
fail_if((condition), "nlerr=%d (%s): %s", \
(error), nl_geterror(error), (message))
+
+Suite *make_nl_attr_suite(void);
+Suite *make_nl_addr_suite(void);
+Suite *make_nl_ematch_tree_clone_suite(void);
+
diff --git a/tools/build_release.sh b/tools/build_release.sh
new file mode 100755
index 00000000..ca63be88
--- /dev/null
+++ b/tools/build_release.sh
@@ -0,0 +1,86 @@
+#!/bin/bash
+
+# script to create libnl release.
+# Steps:
+# - create new commit, bumping version number
+# - run this script
+# - check all is good
+# - tag the commit (signed)
+# git tag -m 'libnl-3.2.26-rc1' -s libnl3_2_26rc1 HEAD
+# - publish the tarballs
+# - push the commit to github
+# - publish the tag on github
+# - publish the tarballs on github
+# - send ANN email
+
+
+die() {
+ printf '%s\n' "$@"
+ exit 1
+}
+
+set -x
+set -e
+
+cd "$(dirname "$0")/.."
+git_dir="$(readlink -f "$(git rev-parse --show-toplevel)")"
+test -f "$git_dir/tools/build_release.sh"
+
+Build() {
+ test "$(git status --porcelain)" = "" || die "there are uncommited changes"
+ git clean -fdx
+ ./autogen.sh
+ ./configure
+ pushd ./doc/
+ ./autogen.sh
+ ./configure --enable-doc
+ popd
+ make -j 5
+ make -C doc
+ make -C doc gendoc
+ make -j 5 distcheck
+ make -C doc dist
+ echo "Build: success"
+}
+
+Copy() {
+ local V="$(ls -1 ./libnl-*.tar.gz | sed -n 's/^\.\/libnl-\(3\.[0-9]\+\.[0-9]\+\(-rc[0-9]\)\?\).tar.gz$/\1/p')"
+ test -n "$V"
+ local REL="libnl-$V"
+ rm -rf "./$REL"
+ mkdir "./$REL"
+ ln "./libnl-$V.tar.gz" "./$REL/"
+ ln "./doc/libnl-doc-$V.tar.gz" "./$REL/"
+ (
+ cd "./$REL/"
+ for F in "libnl-$V.tar.gz" "libnl-doc-$V.tar.gz"; do
+ md5sum "./$F" > "./$F.md5sum"
+ sha256sum "./$F" > "./$F.sha256sum"
+ gpg ${GPG_USER--u thaller@redhat.com} --armor --verbose -o "./$F.sig" --detach-sign "./$F"
+ done
+ )
+ tar -cvf "./$REL.tar" "./$REL/"
+ echo "Copy: success"
+}
+
+BuildAll() {
+ Build || return
+ Copy || return
+ echo "BuildAll: success"
+}
+
+case "$1" in
+ Build)
+ Build
+ ;;
+ Copy)
+ Copy
+ ;;
+ BuildAll)
+ BuildAll
+ ;;
+ *)
+ echo "SYNOPSIS: $0 Build|Copy|BuildAll"
+ echo "WARNING: does a git-clean first!!"
+ ;;
+esac