| //// |
| vim.syntax: asciidoc |
| |
| Copyright (c) 2011 Thomas Graf <tgraf@suug.ch> |
| //// |
| |
| Routing Family Netlink Library (libnl-route) |
| ============================================ |
| Thomas Graf <tgraf@suug.ch> |
| 3.1, Aug 11 2011: |
| |
| == Introduction |
| |
| This library provides APIs to the kernel interfaces of the routing family. |
| |
| |
| NOTE: Work in progress. |
| |
| == Addresses |
| |
| [[route_link]] |
| == Links (Network Devices) |
| |
| The link configuration interface is part of the +NETLINK_ROUTE+ protocol |
| family and implements the following netlink message types: |
| |
| - View and modify the configuration of physical and virtual network devices. |
| - Create and delete virtual network devices (e.g. dummy devices, VLAN devices, |
| tun devices, bridging devices, ...) |
| - View and modify per link network configuration settings (e.g. |
| +net.ipv6.conf.eth0.accept_ra+, +net.ipv4.conf.eth1.forwarding+, ...) |
| |
| .Naming Convention (network device, link, interface) |
| |
| In networking several terms are commonly used to refer to network devices. |
| While they have distinct meanings they have been used interchangeably in |
| the past. Within the Linux kernel, the term _network device_ or _netdev_ is |
| commonly used In user space the term _network interface_ is very common. |
| The routing netlink protocol uses the term _link_ and so does the _iproute2_ |
| utility and most routing daemons. |
| |
| === Netlink Protocol |
| |
| This section describes the protocol semantics of the netlink based link |
| configuration interface. The following messages are defined: |
| |
| [options="header", cols="1,2,2"] |
| |============================================================================== |
| | Message Type | User -> Kernel | Kernel -> User |
| | +RTM_NEWLINK+ | Create or update virtual network device |
| | Reply to +RTM_GETLINK+ request or notification of link added or updated |
| | +RTM_DELLINK+ | Delete virtual network device |
| | Notification of link deleted or disappeared |
| | +RTM_GETLINK+ | Retrieve link configuration and statistics | |
| | +RTM_SETLINK+ | Modify link configuration | |
| |============================================================================== |
| |
| See link:core.html#core_msg_types[Netlink Library - Message Types] for more |
| information on common semantics of these message types. |
| |
| ==== Link Message Format |
| |
| All netlink link messages share a common header (+struct ifinfomsg+) which |
| is appended after the netlink header (+struct nlmsghdr+). |
| |
| image:ifinfomsg.png["Link Message Header"] |
| |
| The meaning of each field may differ depending on the message type. A |
| +struct ifinfomsg+ is defined in +<linux/rtnetlink.h>+ to represent the |
| header. |
| |
| Address Family (8bit):: |
| The address family is usually set to +AF_UNSPEC+ but may be specified in |
| +RTM_GETLINK+ requests to limit the returned links to a specific address |
| family. |
| |
| Link Layer Type (16bit):: |
| Currently only used in kernel->user messages to report the link layer type |
| of a link. The value corresponds to the +ARPHRD_*+ defines found in |
| +<linux/if_arp.h>+. Translation from/to strings can be done using the |
| functions nl_llproto2str()/nl_str2llproto(). |
| |
| Link Index (32bit):: |
| Carries the interface index and is used to identify existing links. |
| |
| Flags (32bit):: |
| In kernel->user messages the value of this field represents the current |
| state of the link flags. In user->kernel messages this field is used to |
| change flags or set the initial flag state of new links. Note that in order |
| to change a flag, the flag must also be set in the _Flags Change Mask_ field. |
| |
| Flags Change Mask (32bit):: |
| The primary use of this field is to specify a mask of flags that should be |
| changed based on the value of the _Flags_ field. A special meaning is given |
| to this field when present in link notifications, see TODO. |
| |
| Attributes (variable):: |
| All link message types may carry netlink attributes. They are defined in the |
| header file <linux/if_link.h> and share the prefix +IFLA_+. |
| |
| ==== Link Message Types |
| |
| .RTM_GETLINK (user->kernel) |
| |
| Lookup link by 1. interface index or 2. link name (+IFLA_IFNAME+) and return |
| a single +RTM_NEWLINK+ message containing the link configuration and statistics |
| or a netlink error message if no such link was found. |
| |
| *Parameters:* |
| |
| * *Address family* |
| ** If the address family is set to +PF_BRIDGE+, only bridging devices will be |
| returned. |
| ** If the address family is set to +PF_INET6+, only ipv6 enabled devices will |
| be returned. |
| |
| *Flags:* |
| |
| * +NLM_F_DUMP+ If set, all links will be returned in form of a multipart |
| message. |
| |
| *Returns:* |
| |
| * +EINVAL+ if neither interface nor link name are set |
| * +ENODEV+ if no link was found |
| * +ENOBUFS+ if allocation failed |
| |
| .RTM_NEWLINK (user->kernel) |
| |
| Creates a new or updates an existing link. Only virtual links may be created |
| but all links may be updated. |
| |
| *Flags:* |
| |
| - +NLM_F_CREATE+ Create link if it does not exist |
| - +NLM_F_EXCL+ Return +EEXIST+ if link already exists |
| |
| *Returns:* |
| |
| - +EINVAL+ malformed message or invalid configuration parameters |
| - +EAFNOSUPPORT+ if an address family specific configuration (+IFLA_AF_SPEC+) |
| is not supported. |
| - +EOPNOTSUPP+ if the link does not support modification of parameters |
| - +EEXIST+ if +NLM_F_EXCL+ was set and the link exists alraedy |
| - +ENODEV+ if the link does not exist and +NLM_F_CREATE+ is not set |
| |
| .RTM_NEWLINK (kernel->user) |
| |
| This message type is used in reply to a +RTM_GETLINK+ request and carries |
| the configuration and statistics of a link. If multiple links need to |
| be sent, the messages will be sent in form of a multipart message. |
| |
| The message type is also used for notifications sent by the kernel to the |
| multicast group +RTNLGRP_LINK+ to inform about various link events. It is |
| therefore recommended to always use a separate link socket for link |
| notifications in order to separate between the two message types. |
| |
| TODO: document how to detect different notifications |
| |
| .RTM_DELLINK (user->kernel) |
| |
| Lookup link by 1. interface index or 2. link name (+IFLA_IFNAME+) and delete |
| the virtual link. |
| |
| *Returns:* |
| |
| * +EINVAL+ if neither interface nor link name are set |
| * +ENODEV+ if no link was found |
| * +ENOTSUPP+ if the operation is not supported (not a virtual link) |
| |
| .RTM_DELLINK (kernel->user) |
| |
| Notification sent by the kernel to the multicast group +RTNLGRP_LINK+ when |
| |
| a. a network device was unregistered (change == ~0) |
| b. a bridging device was deleted (address family will be +PF_BRIDGE+) |
| |
| === Get / List |
| |
| [[link_list]] |
| ==== Get list of links |
| |
| To retrieve the list of links in the kernel, allocate a new link cache |
| using +rtnl_link_alloc_cache()+ to hold the links. It will automatically |
| construct and send a +RTM_GETLINK+ message requesting a dump of all links |
| from the kernel and feed the returned +RTM_NEWLINK+ to the internal link |
| message parser which adds the returned links to the cache. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result) |
| ----- |
| |
| The cache will contain link objects (+struct rtnl_link+, see <<link_object>>) |
| and can be accessed using the standard cache functions. By setting the |
| +family+ parameter to an address family other than +AF_UNSPEC+, the resulting |
| cache will only contain links supporting the specified address family. |
| |
| The following direct search functions are provided to search by interface |
| index and by link name: |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex); |
| struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache, const char *name); |
| ----- |
| |
| .Example: Link Cache |
| |
| [source,c] |
| ----- |
| struct nl_cache *cache; |
| struct rtnl_link *link; |
| |
| if (rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache)) < 0) |
| /* error */ |
| |
| if (!(link = rtnl_link_get_by_name(cache, "eth1"))) |
| /* link does not exist */ |
| |
| /* do something with link */ |
| |
| rtnl_link_put(link); |
| nl_cache_put(cache); |
| ----- |
| |
| [[link_direct_lookup]] |
| ==== Lookup Single Link (Direct Lookup) |
| |
| If only a single link is of interest, the link can be looked up directly |
| without the use of a link cache using the function +rtnl_link_get_kernel()+. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name, struct rtnl_link **result); |
| ----- |
| |
| It will construct and send a +RTM_GETLINK+ request using the parameters |
| provided and wait for a +RTM_NEWLINK+ or netlink error message sent in |
| return. If the link exists, the link is returned as link object |
| (see <<link_object>>). |
| |
| .Example: Direct link lookup |
| [source,c] |
| ----- |
| struct rtnl_link *link; |
| |
| if (rtnl_link_get_kernel(sock, 0, "eth1", &link) < 0) |
| /* error */ |
| |
| /* do something with link */ |
| |
| rtnl_link_put(link); |
| ----- |
| |
| NOTE: While using this function can save a substantial amount of bandwidth |
| on the netlink socket, the result will not be cached, subsequent calls |
| to rtnl_link_get_kernel() will always trigger sending a +RTM_GETLINK+ |
| request. |
| |
| [[link_translate_ifindex]] |
| ==== Translating interface index to link name |
| |
| Applications which require to translate interface index to a link name or |
| vice versa may use the following functions to do so. Both functions require |
| a filled link cache to work with. |
| |
| [source,c] |
| ----- |
| char *rtnl_link_i2name (struct nl_cache *cache, int ifindex, char *dst, size_t len); |
| int rtnl_link_name2i (struct nl_cache *cache, const char *name); |
| ----- |
| |
| === Add / Modify |
| |
| Several types of virtual link can be added on the fly using the function |
| +rtnl_link_add()+. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags); |
| ----- |
| |
| === Delete |
| |
| The deletion of virtual links such as VLAN devices or dummy devices is done |
| using the function +rtnl_link_delete()+. The link passed on to the function |
| can be a link from a link cache or it can be construct with the minimal |
| attributes needed to identify the link. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| int rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *link); |
| ----- |
| |
| The function will construct and send a +RTM_DELLINK+ request message and |
| returns any errors returned by the kernel. |
| |
| .Example: Delete link by name |
| [source,c] |
| ----- |
| struct rtnl_link *link; |
| |
| if (!(link = rtnl_link_alloc())) |
| /* error */ |
| |
| rtnl_link_set_name(link, "my_vlan"); |
| |
| if (rtnl_link_delete(sock, link) < 0) |
| /* error */ |
| |
| rtnl_link_put(link); |
| ----- |
| |
| [[link_object]] |
| === Link Object |
| |
| A link is represented by the structure +struct rtnl_link+. Instances may be |
| created with the function +rtnl_link_alloc()+ or via a link cache (see |
| <<link_list>>) and are freed again using the function +rtnl_link_put()+. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| struct rtnl_link *rtnl_link_alloc(void); |
| void rtnl_link_put(struct rtnl_link *link); |
| ----- |
| |
| [[link_attr_name]] |
| ==== Name |
| The name serves as unique, human readable description of the link. By |
| default, links are named based on their type and then enumerated, e.g. |
| eth0, eth1, ethn but they may be renamed at any time. |
| |
| Kernels >= 2.6.11 support identification by link name. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_name(struct rtnl_link *link, const char *name); |
| char *rtnl_link_get_name(struct rtnl_link *link); |
| ----- |
| |
| *Accepted link name format:* +[^ /]*+ (maximum length: 15 characters) |
| |
| [[link_attr_ifindex]] |
| ==== Interface Index (Identifier) |
| The interface index is an integer uniquely identifying a link. If present |
| in any link message, it will be used to identify an existing link. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex); |
| int rtnl_link_get_ifindex(struct rtnl_link *link); |
| ----- |
| |
| [[link_attr_group]] |
| ==== Group |
| Each link can be assigned a numeric group identifier to group a bunch of links |
| together and apply a set of changes to a group instead of just a single link. |
| |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_group(struct rtnl_link *link, uint32_t group); |
| uint32_t rtnl_link_get_group(struct rtnl_link *link); |
| ----- |
| |
| [[link_attr_address]] |
| ==== Link Layer Address |
| The link layer address (e.g. MAC address). |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr); |
| struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link); |
| ----- |
| |
| [[link_attr_broadcast]] |
| ==== Broadcast Address |
| The link layer broadcast address |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *addr); |
| struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link); |
| ----- |
| |
| [[link_attr_mtu]] |
| ==== MTU (Maximum Transmission Unit) |
| The maximum transmission unit specifies the maximum packet size a network |
| device can transmit or receive. This value may be lower than the capability |
| of the physical network device. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu); |
| unsigned int rtnl_link_get_mtu(struct rtnl_link *link); |
| ----- |
| |
| [[link_attr_flags]] |
| ==== Flags |
| The flags of a link enable or disable various link features or inform about |
| the state of the link. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags); |
| void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags); |
| unsigned int rtnl_link_get_flags(struct rtnl_link *link); |
| ----- |
| |
| [options="compact"] |
| [horizontal] |
| IFF_UP:: Link is up (administratively) |
| IFF_RUNNING:: Link is up and carrier is OK (RFC2863 OPER_UP) |
| IFF_LOWER_UP:: Link layer is operational |
| IFF_DORMANT:: Driver signals dormant |
| IFF_BROADCAST:: Link supports broadcasting |
| IFF_MULTICAST:: Link supports multicasting |
| IFF_ALLMULTI:: Link supports multicast routing |
| IFF_DEBUG:: Tell driver to do debugging (currently unused) |
| IFF_LOOPBACK:: Link loopback network |
| IFF_POINTOPOINT:: Point-to-point link |
| IFF_NOARP:: ARP is not supported |
| IFF_PROMISC:: Status of promiscuous mode |
| IFF_MASTER:: Master of a load balancer (bonding) |
| IFF_SLAVE:: Slave to a master link |
| IFF_PORTSEL:: Driver supports setting media type (only used by ARM ethernet) |
| IFF_AUTOMEDIA:: Link selects port automatically (only used by ARM ethernet) |
| IFF_ECHO:: Echo sent packets (testing feature, CAN only) |
| IFF_DYNAMIC:: Unused (BSD compatibility) |
| IFF_NOTRAILERS:: Unused (BSD compatibility) |
| |
| To translate a link flag to a link flag name or vice versa: |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| char *rtnl_link_flags2str(int flags, char *buf, size_t size); |
| int rtnl_link_str2flags(const char *flag_name); |
| ----- |
| |
| [[link_attr_txqlen]] |
| ==== Transmission Queue Length |
| |
| The transmission queue holds packets before packets are delivered to |
| the driver for transmission. It is usually specified in number of |
| packets but the unit may be specific to the link type. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen); |
| unsigned int rtnl_link_get_txqlen(struct rtnl_link *link); |
| ----- |
| |
| [[link_attr_operstate]] |
| ==== Operational Status |
| The operational status has been introduced to provide extended information |
| on the link status. Traditionally the link state has been described using |
| the link flags +IFF_UP, IFF_RUNNING, IFF_LOWER_UP+, and +IFF_DORMANT+ which |
| was no longer sufficient for some link types. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t state); |
| uint8_t rtnl_link_get_operstate(struct rtnl_link *link); |
| ----- |
| |
| [options="compact"] |
| [horizontal] |
| IF_OPER_UNKNOWN:: Unknown state |
| IF_OPER_NOTPRESENT:: Link not present |
| IF_OPER_DOWN:: Link down |
| IF_OPER_LOWERLAYERDOWN:: L1 down |
| IF_OPER_TESTING:: Testing |
| IF_OPER_DORMANT:: Dormant |
| IF_OPER_UP:: Link up |
| |
| Translation of operational status code to string and vice versa: |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| char *rtnl_link_operstate2str(uint8_t state, char *buf, size_t size); |
| int rtnl_link_str2operstate(const char *name); |
| ----- |
| |
| [[link_attr_mode]] |
| ==== Mode |
| Currently known link modes are: |
| |
| [options="compact"] |
| [horizontal] |
| IF_LINK_MODE_DEFAULT:: Default link mode |
| IF_LINK_MODE_DORMANT:: Limit upward transition to dormant |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t mode); |
| uint8_t rtnl_link_get_linkmode(struct rtnl_link *link); |
| ----- |
| |
| Translation of link mode to string and vice versa: |
| |
| [source,c] |
| ----- |
| char *rtnl_link_mode2str(uint8_t mode, char *buf, size_t len); |
| uint8_t rtnl_link_str2mode(const char *name); |
| ----- |
| |
| [[link_attr_alias]] |
| ==== IfAlias |
| Alternative name for the link, primarly used for SNMP IfAlias. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| const char *rtnl_link_get_ifalias(struct rtnl_link *link); |
| void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias); |
| ----- |
| |
| *Length limit:* 256 |
| |
| [[link_attr_arptype]] |
| ==== Hardware Type |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| #include <linux/if_arp.h> |
| |
| void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype); |
| unsigned int rtnl_link_get_arptype(struct rtnl_link *link); |
| ---- |
| |
| Translation of hardware type to character string and vice versa: |
| |
| [source,c] |
| ----- |
| #include <netlink/utils.h> |
| |
| char *nl_llproto2str(int arptype, char *buf, size_t len); |
| int nl_str2llproto(const char *name); |
| ----- |
| |
| [[link_attr_qdisc]] |
| ==== Qdisc |
| The name of the queueing discipline used by the link is of informational |
| nature only. It is a read-only attribute provided by the kernel and cannot |
| be modified. The set function is provided solely for the purpose of creating |
| link objects to be used for comparison. |
| |
| For more information on how to modify the qdisc of a link, see section |
| <<route_tc>>. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_qdisc(struct rtnl_link *link, const char *name); |
| char *rtnl_link_get_qdisc(struct rtnl_link *link); |
| ----- |
| |
| [[link_attr_promiscuity]] |
| ==== Promiscuity |
| The number of subsystem currently depending on the link being promiscuous mode. |
| A value of 0 indicates that the link is not in promiscuous mode. It is a |
| read-only attribute provided by the kernel and cannot be modified. The set |
| function is provided solely for the purpose of creating link objects to be |
| used for comparison. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_promiscuity(struct rtnl_link *link, uint32_t count); |
| uint32_t rtnl_link_get_promiscuity(struct rtnl_link *link); |
| ----- |
| |
| [[link_num_rxtx_queues]] |
| ==== RX/TX Queues |
| The number of RX/TX queues the link provides. The attribute is writable but |
| will only be considered when creating a new network device via netlink. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| void rtnl_link_set_num_tx_queues(struct rtnl_link *link, uint32_t nqueues); |
| uint32_t rtnl_link_get_num_tx_queues(struct rtnl_link *link); |
| |
| void rtnl_link_set_num_rx_queues(struct rtnl_link *link, uint32_t nqueues); |
| uint32_t rtnl_link_get_num_rx_queues(struct rtnl_link *link); |
| ----- |
| |
| [[link_attr_weight]] |
| ==== Weight |
| This attribute is unused and obsoleted in all recent kernels. |
| |
| |
| [[link_modules]] |
| === Modules |
| |
| [[link_bonding]] |
| ==== Bonding |
| |
| .Example: Add bonding link |
| [source,c] |
| ----- |
| #include <netlink/route/link.h> |
| |
| struct rtnl_link *link; |
| |
| link = rtnl_link_bond_alloc(); |
| rtnl_link_set_name(link, "my_bond"); |
| |
| /* requires admin privileges */ |
| if (rtnl_link_add(sk, link, NLM_F_CREATE) < 0) |
| /* error */ |
| |
| rtnl_link_put(link); |
| ----- |
| |
| [[link_vlan]] |
| ==== VLAN |
| |
| [source,c] |
| ----- |
| extern char * rtnl_link_vlan_flags2str(int, char *, size_t); |
| extern int rtnl_link_vlan_str2flags(const char *); |
| |
| extern int rtnl_link_vlan_set_id(struct rtnl_link *, int); |
| extern int rtnl_link_vlan_get_id(struct rtnl_link *); |
| |
| extern int rtnl_link_vlan_set_flags(struct rtnl_link *, |
| unsigned int); |
| extern int rtnl_link_vlan_unset_flags(struct rtnl_link *, |
| unsigned int); |
| extern unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *); |
| |
| extern int rtnl_link_vlan_set_ingress_map(struct rtnl_link *, |
| int, uint32_t); |
| extern uint32_t * rtnl_link_vlan_get_ingress_map(struct rtnl_link *); |
| |
| extern int rtnl_link_vlan_set_egress_map(struct rtnl_link *, |
| uint32_t, int); |
| extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *, |
| int *); |
| ----- |
| |
| .Example: Add a VLAN device |
| [source,c] |
| ----- |
| struct rtnl_link *link; |
| int master_index; |
| |
| /* lookup interface index of eth0 */ |
| if (!(master_index = rtnl_link_name2i(link_cache, "eth0"))) |
| /* error */ |
| |
| /* allocate new link object of type vlan */ |
| link = rtnl_link_vlan_alloc(); |
| |
| /* set eth0 to be our master device */ |
| rtnl_link_set_link(link, master_index); |
| |
| rtnl_link_vlan_set_id(link, 10); |
| |
| if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) |
| /* error */ |
| |
| rtnl_link_put(link); |
| ----- |
| |
| [[link_macvlan]] |
| ==== MACVLAN |
| |
| [source,c] |
| ----- |
| extern struct rtnl_link *rtnl_link_macvlan_alloc(void); |
| |
| extern int rtnl_link_is_macvlan(struct rtnl_link *); |
| |
| extern char * rtnl_link_macvlan_mode2str(int, char *, size_t); |
| 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 int rtnl_link_macvlan_set_mode(struct rtnl_link *, |
| uint32_t); |
| extern uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *); |
| |
| extern int rtnl_link_macvlan_set_flags(struct rtnl_link *, |
| uint16_t); |
| extern int rtnl_link_macvlan_unset_flags(struct rtnl_link *, |
| uint16_t); |
| extern uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *); |
| ----- |
| |
| .Example: Add a MACVLAN 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 macvlan */ |
| link = rtnl_link_macvlan_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_macvlan_set_mode(link, rtnl_link_macvlan_str2mode("bridge")); |
| |
| if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) |
| /* error */ |
| |
| 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 |
| |
| [source,c] |
| ----- |
| extern struct rtnl_link *rtnl_link_vxlan_alloc(void); |
| |
| 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_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_local(struct rtnl_link *, struct nl_addr *); |
| extern int rtnl_link_vxlan_get_local(struct rtnl_link *, struct nl_addr **); |
| |
| extern int rtnl_link_vxlan_set_ttl(struct rtnl_link *, uint8_t); |
| extern int rtnl_link_vxlan_get_ttl(struct rtnl_link *); |
| |
| extern int rtnl_link_vxlan_set_tos(struct rtnl_link *, uint8_t); |
| extern int rtnl_link_vxlan_get_tos(struct rtnl_link *); |
| |
| extern int rtnl_link_vxlan_set_learning(struct rtnl_link *, uint8_t); |
| extern int rtnl_link_vxlan_get_learning(struct rtnl_link *); |
| extern int rtnl_link_vxlan_enable_learning(struct rtnl_link *); |
| extern int rtnl_link_vxlan_disable_learning(struct rtnl_link *); |
| |
| extern int rtnl_link_vxlan_set_ageing(struct rtnl_link *, uint32_t); |
| extern int rtnl_link_vxlan_get_ageing(struct rtnl_link *, uint32_t *); |
| |
| extern int rtnl_link_vxlan_set_limit(struct rtnl_link *, uint32_t); |
| extern int rtnl_link_vxlan_get_limit(struct rtnl_link *, uint32_t *); |
| |
| extern int rtnl_link_vxlan_set_port_range(struct rtnl_link *, |
| struct ifla_vxlan_port_range *); |
| extern int rtnl_link_vxlan_get_port_range(struct rtnl_link *, |
| struct ifla_vxlan_port_range *); |
| |
| extern int rtnl_link_vxlan_set_proxy(struct rtnl_link *, uint8_t); |
| extern int rtnl_link_vxlan_get_proxy(struct rtnl_link *); |
| extern int rtnl_link_vxlan_enable_proxy(struct rtnl_link *); |
| extern int rtnl_link_vxlan_disable_proxy(struct rtnl_link *); |
| |
| extern int rtnl_link_vxlan_set_rsc(struct rtnl_link *, uint8_t); |
| extern int rtnl_link_vxlan_get_rsc(struct rtnl_link *); |
| extern int rtnl_link_vxlan_enable_rsc(struct rtnl_link *); |
| extern int rtnl_link_vxlan_disable_rsc(struct rtnl_link *); |
| |
| extern int rtnl_link_vxlan_set_l2miss(struct rtnl_link *, uint8_t); |
| extern int rtnl_link_vxlan_get_l2miss(struct rtnl_link *); |
| extern int rtnl_link_vxlan_enable_l2miss(struct rtnl_link *); |
| extern int rtnl_link_vxlan_disable_l2miss(struct rtnl_link *); |
| |
| extern int rtnl_link_vxlan_set_l3miss(struct rtnl_link *, uint8_t); |
| 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 *); |
| ----- |
| |
| .Example: Add a VXLAN device |
| [source,c] |
| ----- |
| struct rtnl_link *link; |
| struct nl_addr* addr; |
| |
| /* allocate new link object of type vxlan */ |
| link = rtnl_link_vxlan_alloc(); |
| |
| /* set interface name */ |
| rtnl_link_set_name(link, "vxlan128"); |
| |
| /* set VXLAN network identifier */ |
| if ((err = rtnl_link_vxlan_set_id(link, 128)) < 0) |
| /* error */ |
| |
| /* set multicast address to join */ |
| if ((err = nl_addr_parse("239.0.0.1", AF_INET, &addr)) < 0) |
| /* error */ |
| |
| if ((err = rtnl_link_set_group(link, addr)) < 0) |
| /* error */ |
| |
| nl_addr_put(addr); |
| |
| if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) |
| /* error */ |
| |
| rtnl_link_put(link); |
| ----- |
| |
| [[link_ipip]] |
| ==== IPIP |
| |
| [source,c] |
| ----- |
| 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_ipip_set_link(struct rtnl_link *link, uint32_t index); |
| extern uint32_t rtnl_link_ipip_get_link(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipip_set_local(struct rtnl_link *link, uint32_t addr); |
| extern uint32_t rtnl_link_ipip_get_local(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipip_set_remote(struct rtnl_link *link, uint32_t addr); |
| extern uint32_t rtnl_link_ipip_get_remote(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipip_set_ttl(struct rtnl_link *link, uint8_t ttl); |
| extern uint8_t rtnl_link_ipip_get_ttl(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipip_set_tos(struct rtnl_link *link, uint8_t tos); |
| extern uint8_t rtnl_link_ipip_get_tos(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipip_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc); |
| extern uint8_t rtnl_link_ipip_get_pmtudisc(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipip_set_fwmark(struct rtnl_link *link, uint32_t fwmark); |
| extern int rtnl_link_ipip_get_fwmark(struct rtnl_link *link, uint32_t *fwmark); |
| |
| ----- |
| |
| .Example: Add an ipip tunnel device |
| [source,c] |
| ----- |
| struct rtnl_link *link |
| struct in_addr addr |
| |
| /* allocate new link object of type ipip */ |
| if(!(link = rtnl_link_ipip_alloc())) |
| /* error */ |
| |
| /* set ipip tunnel name */ |
| if ((err = rtnl_link_set_name(link, "ipip-tun")) < 0) |
| /* error */ |
| |
| /* set link index */ |
| if ((err = rtnl_link_ipip_set_link(link, if_index)) < 0) |
| /* error */ |
| |
| /* set local address */ |
| inet_pton(AF_INET, "192.168.254.12", &addr.s_addr); |
| if ((err = rtnl_link_ipip_set_local(link, addr.s_addr)) < 0) |
| /* error */ |
| |
| /* set remote address */ |
| inet_pton(AF_INET, "192.168.254.13", &addr.s_addr |
| if ((err = rtnl_link_ipip_set_remote(link, addr.s_addr)) < 0) |
| /* error */ |
| |
| /* set tunnel ttl */ |
| if ((err = rtnl_link_ipip_set_ttl(link, 64)) < 0) |
| /* error */ |
| |
| if((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) |
| /* error */ |
| |
| rtnl_link_put(link); |
| ----- |
| |
| [[link_ipgre]] |
| ==== IPGRE |
| |
| [source,c] |
| ----- |
| extern struct rtnl_link *rtnl_link_ipgre_alloc(void); |
| extern int rtnl_link_ipgre_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); |
| |
| extern int rtnl_link_ipgre_set_iflags(struct rtnl_link *link, uint16_t iflags); |
| extern uint16_t rtnl_link_get_iflags(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipgre_set_oflags(struct rtnl_link *link, uint16_t oflags); |
| extern uint16_t rtnl_link_get_oflags(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipgre_set_ikey(struct rtnl_link *link, uint32_t ikey); |
| extern uint32_t rtnl_link_get_ikey(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipgre_set_okey(struct rtnl_link *link, uint32_t okey); |
| extern uint32_t rtnl_link_get_okey(struct rtnl_link *link) |
| |
| extern int rtnl_link_ipgre_set_local(struct rtnl_link *link, uint32_t addr); |
| extern uint32_t rtnl_link_ipgre_get_local(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipgre_set_remote(struct rtnl_link *link, uint32_t addr); |
| extern uint32_t rtnl_link_ipgre_get_remote(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipgre_set_ttl(struct rtnl_link *link, uint8_t ttl); |
| extern uint8_t rtnl_link_ipgre_get_ttl(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipgre_set_tos(struct rtnl_link *link, uint8_t tos); |
| extern uint8_t rtnl_link_ipgre_get_tos(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipgre_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc); |
| extern uint8_t rtnl_link_ipgre_get_pmtudisc(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipgre_set_fwmark(struct rtnl_link *link, uint32_t fwmark); |
| extern int rtnl_link_ipgre_get_fwmark(struct rtnl_link *link, uint32_t *fwmark); |
| |
| ----- |
| |
| .Example: Add an ipgre tunnel device |
| [source,c] |
| ----- |
| struct rtnl_link *link |
| struct in_addr addr |
| |
| /* allocate new link object of type ipgre */ |
| if(!(link = rtnl_link_ipgre_alloc())) |
| /* error */ |
| |
| /* set ipgre tunnel name */ |
| if ((err = rtnl_link_set_name(link, "ipgre-tun")) < 0) |
| /* error */ |
| |
| /* set link index */ |
| if ((err = rtnl_link_ipgre_set_link(link, if_index)) < 0) |
| /* error */ |
| |
| /* set local address */ |
| inet_pton(AF_INET, "192.168.254.12", &addr.s_addr); |
| if ((err = rtnl_link_ipgre_set_local(link, addr.s_addr)) < 0) |
| /* error */ |
| |
| /* set remote address */ |
| inet_pton(AF_INET, "192.168.254.13", &addr.s_addr |
| if ((err = rtnl_link_ipgre_set_remote(link, addr.s_addr)) < 0) |
| /* error */ |
| |
| /* set tunnel ttl */ |
| if ((err = rtnl_link_ipgre_set_ttl(link, 64)) < 0) |
| /* error */ |
| |
| if((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) |
| /* error */ |
| |
| rtnl_link_put(link); |
| ----- |
| |
| [[link_sit]] |
| ==== SIT |
| |
| [source,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_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_iflags(struct rtnl_link *link, uint16_t iflags); |
| extern uint16_t rtnl_link_get_iflags(struct rtnl_link *link); |
| |
| extern int rtnl_link_sit_set_oflags(struct rtnl_link *link, uint16_t oflags); |
| extern uint16_t rtnl_link_get_oflags(struct rtnl_link *link); |
| |
| extern int rtnl_link_sit_set_ikey(struct rtnl_link *link, uint32_t ikey); |
| extern uint32_t rtnl_link_get_ikey(struct rtnl_link *link); |
| |
| extern int rtnl_link_sit_set_okey(struct rtnl_link *link, uint32_t okey); |
| extern uint32_t rtnl_link_get_okey(struct rtnl_link *link) |
| |
| extern int rtnl_link_sit_set_local(struct rtnl_link *link, uint32_t addr); |
| 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); |
| |
| extern int rtnl_link_sit_set_ttl(struct rtnl_link *link, uint8_t ttl); |
| extern uint8_t rtnl_link_sit_get_ttl(struct rtnl_link *link); |
| |
| extern int rtnl_link_sit_set_tos(struct rtnl_link *link, uint8_t tos); |
| extern uint8_t rtnl_link_sit_get_tos(struct rtnl_link *link); |
| |
| extern int rtnl_link_sit_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc); |
| extern uint8_t rtnl_link_sit_get_pmtudisc(struct rtnl_link *link); |
| |
| extern int rtnl_link_sit_set_fwmark(struct rtnl_link *link, uint32_t fwmark); |
| extern int rtnl_link_sit_get_fwmark(struct rtnl_link *link, uint32_t *fwmark); |
| |
| ----- |
| |
| .Example: Add a sit tunnel device |
| [source,c] |
| ----- |
| struct rtnl_link *link |
| struct in_addr addr |
| |
| /* allocate new link object of type sit */ |
| if(!(link = rtnl_link_sit_alloc())) |
| /* error */ |
| |
| /* set sit tunnel name */ |
| if ((err = rtnl_link_set_name(link, "sit-tun")) < 0) |
| /* error */ |
| |
| /* set link index */ |
| if ((err = rtnl_link_sit_set_link(link, if_index)) < 0) |
| /* error */ |
| |
| /* set local address */ |
| inet_pton(AF_INET, "192.168.254.12", &addr.s_addr); |
| if ((err = rtnl_link_sit_set_local(link, addr.s_addr)) < 0) |
| /* error */ |
| |
| /* set remote address */ |
| inet_pton(AF_INET, "192.168.254.13", &addr.s_addr |
| if ((err = rtnl_link_sit_set_remote(link, addr.s_addr)) < 0) |
| /* error */ |
| |
| /* set tunnel ttl */ |
| if ((err = rtnl_link_sit_set_ttl(link, 64)) < 0) |
| /* error */ |
| |
| if((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) |
| /* error */ |
| |
| rtnl_link_put(link); |
| ----- |
| |
| |
| [[link_ipvti]] |
| ==== IPVTI |
| |
| [source,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_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_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_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); |
| |
| extern int rtnl_link_ipvti_set_remote(struct rtnl_link *link, uint32_t addr); |
| extern uint32_t rtnl_link_ipvti_get_remote(struct rtnl_link *link); |
| |
| extern int rtnl_link_ipvti_set_fwmark(struct rtnl_link *link, uint32_t fwmark); |
| extern int rtnl_link_ipvti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark); |
| |
| ----- |
| |
| .Example: Add an ipvti tunnel device |
| [source,c] |
| ----- |
| struct rtnl_link *link |
| struct in_addr addr |
| |
| /* allocate new link object of type ipvti */ |
| if(!(link = rtnl_link_ipvti_alloc())) |
| /* error */ |
| |
| /* set ipvti tunnel name */ |
| if ((err = rtnl_link_set_name(link, "ipvti-tun")) < 0) |
| /* error */ |
| |
| /* set link index */ |
| if ((err = rtnl_link_ipvti_set_link(link, if_index)) < 0) |
| /* error */ |
| |
| /* set local address */ |
| inet_pton(AF_INET, "192.168.254.12", &addr.s_addr); |
| if ((err = rtnl_link_ipvti_set_local(link, addr.s_addr)) < 0) |
| /* error */ |
| |
| /* set remote address */ |
| inet_pton(AF_INET, "192.168.254.13", &addr.s_addr |
| if ((err = rtnl_link_ipvti_set_remote(link, addr.s_addr)) < 0) |
| /* error */ |
| |
| if((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) |
| /* error */ |
| |
| rtnl_link_put(link); |
| ----- |
| |
| [[link_ip6tnl]] |
| ==== IP6TNL |
| |
| [source,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_ip6_tnl_set_link(struct rtnl_link *link, uint32_t index); |
| extern uint32_t rtnl_link_ip6_tnl_get_link(struct rtnl_link *link); |
| |
| extern int rtnl_link_ip6_tnl_set_local(struct rtnl_link *link, struct in6_addr *); |
| extern int rtnl_link_ip6_tnl_get_local(struct rtnl_link *link, struct in6_addr *); |
| |
| extern int rtnl_link_ip6_tnl_set_remote(struct rtnl_link *link, struct in6_addr *); |
| extern int rtnl_link_ip6_tnl_get_remote(struct rtnl_link *link, struct in6_addr *); |
| |
| extern int rtnl_link_ip6_tnl_set_ttl(struct rtnl_link *link, uint8_t ttl); |
| extern uint8_t rtnl_link_ip6_tnl_get_ttl(struct rtnl_link *link); |
| |
| extern int rtnl_link_ip6_tnl_set_tos(struct rtnl_link *link, uint8_t tos); |
| extern uint8_t rtnl_link_ip6_tnl_get_tos(struct rtnl_link *link); |
| |
| extern int rtnl_link_ip6_tnl_set_encaplimit(struct rtnl_link *link, uint8_t encap_limit); |
| extern uint8_t rtnl_link_ip6_tnl_get_encaplimit(struct rtnl_link *link); |
| |
| extern int rtnl_link_ip6_tnl_set_flags(struct rtnl_link *link, uint32_t flags); |
| extern uint32_t rtnl_link_ip6_tnl_get_flags(struct rtnl_link *link); |
| |
| extern uint32_t rtnl_link_ip6_tnl_get_flowinfo(struct rtnl_link *link); |
| extern int rtnl_link_ip6_tnl_set_flowinfo(struct rtnl_link *link, uint32_t flowinfo); |
| |
| 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); |
| |
| extern int rtnl_link_ip6_tnl_set_fwmark(struct rtnl_link *link, uint32_t fwmark); |
| extern int rtnl_link_ip6_tnl_get_fwmark(struct rtnl_link *link, uint32_t *fwmark); |
| |
| ----- |
| |
| .Example: Add an ip6tnl tunnel device |
| [source,c] |
| ----- |
| struct rtnl_link *link |
| struct in6_addr addr |
| |
| link = rtnl_link_ip6_tnl_alloc(); |
| |
| rtnl_link_set_name(link, "ip6tnl-tun"); |
| rtnl_link_ip6_tnl_set_link(link, if_index); |
| |
| inet_pton(AF_INET6, "2607:f0d0:1002:51::4", &addr); |
| rtnl_link_ip6_tnl_set_local(link, &addr); |
| |
| inet_pton(AF_INET6, "2607:f0d0:1002:52::5", &addr); |
| rtnl_link_ip6_tnl_set_remote(link, &addr); |
| |
| rtnl_link_add(sk, link, NLM_F_CREATE); |
| rtnl_link_put(link); |
| |
| ----- |
| |
| [[link_ip6gre]] |
| ==== IP6GRE |
| |
| [source,c] |
| ---- |
| extern int rtnl_link_is_ip6gre(struct rtnl_link *link); |
| |
| extern struct rtnl_link *rtnl_link_ip6gre_alloc(void); |
| extern int rtnl_link_ip6gre_add(struct nl_sock *sk, const char *name); |
| |
| extern int rtnl_link_ip6gre_set_link(struct rtnl_link *link, uint32_t index); |
| extern int rtnl_link_ip6gre_get_link(struct rtnl_link *link, uint32_t *index); |
| |
| extern int rtnl_link_ip6gre_set_iflags(struct rtnl_link *link, uint16_t iflags); |
| extern int rtnl_link_ip6gre_get_iflags(struct rtnl_link *link, uint16_t *iflags); |
| |
| extern int rtnl_link_ip6gre_set_oflags(struct rtnl_link *link, uint16_t oflags); |
| extern int rtnl_link_ip6gre_get_oflags(struct rtnl_link *link, uint16_t *oflags); |
| |
| extern int rtnl_link_ip6gre_set_ikey(struct rtnl_link *link, uint32_t ikey); |
| extern int rtnl_link_ip6gre_get_ikey(struct rtnl_link *link, uint32_t *ikey); |
| |
| extern int rtnl_link_ip6gre_set_okey(struct rtnl_link *link, uint32_t okey); |
| extern int rtnl_link_ip6gre_get_okey(struct rtnl_link *link, uint32_t *okey); |
| |
| extern int rtnl_link_ip6gre_set_local(struct rtnl_link *link, struct in6_addr *local); |
| extern int rtnl_link_ip6gre_get_local(struct rtnl_link *link, struct in6_addr *local); |
| |
| extern int rtnl_link_ip6gre_set_remote(struct rtnl_link *link, struct in6_addr *remote); |
| extern int rtnl_link_ip6gre_get_remote(struct rtnl_link *link, struct in6_addr *remote); |
| |
| extern int rtnl_link_ip6gre_set_ttl(struct rtnl_link *link, uint8_t ttl); |
| extern int rtnl_link_ip6gre_get_ttl(struct rtnl_link *link, uint8_t *ttl); |
| |
| extern int rtnl_link_ip6gre_set_encaplimit(struct rtnl_link *link, uint8_t encaplimit); |
| extern int rtnl_link_ip6gre_get_encaplimit(struct rtnl_link *link, uint8_t *encaplimit); |
| |
| extern int rtnl_link_ip6gre_set_flowinfo(struct rtnl_link *link, uint32_t flowinfo); |
| extern int rtnl_link_ip6gre_get_flowinfo(struct rtnl_link *link, uint32_t *flowinfo); |
| |
| extern int rtnl_link_ip6gre_set_flags(struct rtnl_link *link, uint32_t flags); |
| extern int rtnl_link_ip6gre_get_flags(struct rtnl_link *link, uint32_t *flags); |
| |
| extern int rtnl_link_ip6gre_set_fwmark(struct rtnl_link *link, uint32_t fwmark); |
| extern int rtnl_link_ip6gre_get_fwmark(struct rtnl_link *link, uint32_t *fwmark); |
| |
| ---- |
| |
| .Example: Add an ip6gre tunnel device |
| [source,c] |
| ---- |
| struct rtnl_link *link |
| struct in6_addr addr |
| |
| link = rtnl_link_ip6gre_alloc(); |
| |
| rtnl_link_set_name(link, "ip6gre-tun"); |
| rtnl_link_ip6gre_set_link(link, if_index); |
| |
| inet_pton(AF_INET6, "2607:f0d0:1002:51::4", &addr); |
| rtnl_link_ip6gre_set_local(link, &addr); |
| |
| inet_pton(AF_INET6, "2607:f0d0:1002:52::5", &addr); |
| rtnl_link_ip6gre_set_remote(link, &addr); |
| |
| rtnl_link_add(sk, link, NLM_F_CREATE); |
| rtnl_link_put(link); |
| |
| ----- |
| |
| [[link_ip6vti]] |
| ==== IP6VTI |
| |
| [source,c] |
| ---- |
| int rtnl_link_is_ip6vti(struct rtnl_link *link); |
| |
| extern struct rtnl_link *rtnl_link_ip6vti_alloc(void); |
| extern int rtnl_link_ip6vti_add(struct nl_sock *sk, const char *name); |
| |
| extern int rtnl_link_ip6vti_set_link(struct rtnl_link *link, uint32_t index); |
| extern int rtnl_link_ip6vti_get_link(struct rtnl_link *link, uint32_t *index); |
| |
| extern int rtnl_link_ip6vti_set_ikey(struct rtnl_link *link, uint32_t ikey); |
| extern int rtnl_link_ip6vti_get_ikey(struct rtnl_link *link, uint32_t *ikey); |
| |
| extern int rtnl_link_ip6vti_set_okey(struct rtnl_link *link, uint32_t okey); |
| extern int rtnl_link_ip6vti_get_okey(struct rtnl_link *link, uint32_t *okey); |
| |
| extern int rtnl_link_ip6vti_set_local(struct rtnl_link *link, struct in6_addr *local); |
| extern int rtnl_link_ip6vti_get_local(struct rtnl_link *link, struct in6_addr *remote); |
| |
| extern int rtnl_link_ip6vti_set_remote(struct rtnl_link *link, struct in6_addr *remote); |
| extern int rtnl_link_ip6vti_get_remote(struct rtnl_link *link, struct in6_addr *remote); |
| |
| extern int rtnl_link_ip6vti_set_fwmark(struct rtnl_link *link, uint32_t fwmark); |
| extern int rtnl_link_ip6vti_get_fwmark(struct rtnl_link *link, uint32_t *fwmark); |
| |
| ---- |
| |
| .Example: Add an ip6vti tunnel device |
| [source,c] |
| ---- |
| struct rtnl_link *link |
| struct in6_addr addr |
| |
| link = rtnl_link_ip6vti_alloc(); |
| |
| rtnl_link_set_name(link, "ip6vti-tun"); |
| rtnl_link_ip6vti_set_link(link, if_index); |
| |
| inet_pton(AF_INET6, "2607:f0d0:1002:51::4", &addr); |
| rtnl_link_ip6vti_set_local(link, &addr); |
| |
| inet_pton(AF_INET6, "2607:f0d0:1002:52::5", &addr); |
| rtnl_link_ip6vti_set_remote(link, &addr); |
| |
| rtnl_link_add(sk, link, NLM_F_CREATE); |
| 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 |
| |
| [[route_tc]] |
| == Traffic Control |
| |
| The traffic control architecture allows the queueing and |
| prioritization of packets before they are enqueued to the network |
| driver. To a limited degree it is also possible to take control of |
| network traffic as it enters the network stack. |
| |
| The architecture consists of three different types of modules: |
| |
| - *Queueing disciplines (qdisc)* provide a mechanism to enqueue packets |
| in different forms. They may be used to implement fair queueing, |
| prioritization of differentiated services, enforce bandwidth |
| limitations, or even to simulate network behaviour such as packet |
| loss and packet delay. Qdiscs can be classful in which case they |
| allow traffic classes described in the next paragraph to be attached |
| to them. |
| |
| - *Traffic classes (class)* are supported by several qdiscs to build |
| a tree structure for different types of traffic. Each class may be |
| assigned its own set of attributes such as bandwidth limits or |
| queueing priorities. Some qdiscs even allow borrowing of bandwidth |
| between classes. |
| |
| - *Classifiers (cls)* are used to decide which qdisc/class the packet |
| should be enqueued to. Different types of classifiers exists, |
| ranging from classification based on protocol header values to |
| classification based on packet priority or firewall marks. |
| Additionally most classifiers support *extended matches (ematch)* |
| which allow extending classifiers by a set of matcher modules, and |
| *actions* which allow classifiers to take actions such as mangling, |
| mirroring, or even rerouting of packets. |
| |
| .Default Qdisc |
| |
| The default qdisc used on all network devices is `pfifo_fast`. |
| Network devices which do not require a transmit queue such as the |
| loopback device do not have a default qdisc attached. The `pfifo_fast` |
| qdisc provides three bands to prioritize interactive traffic over bulk |
| traffic. Classification is based on the packet priority (diffserv). |
| |
| image:qdisc_default.png["Default Qdisc"] |
| |
| .Multiqueue Default Qdisc |
| |
| If the network device provides multiple transmit queues the `mq` |
| qdisc is used by default. It will automatically create a separate |
| class for each transmit queue available and will also replace |
| the single per device tx lock with a per queue lock. |
| |
| image:qdisc_mq.png["Multiqueue default Qdisc"] |
| |
| .Example of a customized classful qdisc setup |
| |
| The following figure illustrates a possible combination of different |
| queueing and classification modules to implement quality of service |
| needs. |
| |
| image:tc_overview.png["Classful Qdisc diagram"] |
| |
| === Traffic Control Object |
| |
| Each type traffic control module (qdisc, class, classifier) is |
| represented by its own structure. All of them are based on the traffic |
| control object represented by `struct rtnl_tc` which itself is based |
| on the generic object `struct nl_object` to make it cacheable. The |
| traffic control object contains all attributes, implementation details |
| and statistics that are shared by all of the traffic control object |
| types. |
| |
| image:tc_obj.png["struct rtnl_tc hierarchy"] |
| |
| It is not possible to allocate a `struct rtnl_tc` object, instead the |
| actual tc object types must be allocated directly using |
| `rtnl_qdisc_alloc()`, `rtnl_class_alloc()`, `rtnl_cls_alloc()` and |
| then casted to `struct rtnl_tc` using the `TC_CAST()` macro. |
| |
| .Usage Example: Allocation, Casting, Freeing |
| [source,c] |
| ----- |
| #include <netlink/route/tc.h> |
| #include <netlink/route/qdisc.h> |
| |
| struct rtnl_qdisc *qdisc; |
| |
| /* Allocation of a qdisc object */ |
| qdisc = rtnl_qdisc_alloc(); |
| |
| /* Cast the qdisc to a tc object using TC_CAST() to use rtnl_tc_ functions. */ |
| rtnl_tc_set_mpu(TC_CAST(qdisc), 64); |
| |
| /* Free the qdisc object */ |
| rtnl_qdisc_put(qdisc); |
| ----- |
| |
| [[tc_attr]] |
| ==== Attributes |
| |
| Handle:: |
| The handle uniquely identifies a tc object and is used to refer |
| to other tc objects when constructing tc trees. |
| + |
| [source,c] |
| ----- |
| void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t handle); |
| uint32_t rtnl_tc_get_handle(struct rtnl_tc *tc); |
| ----- |
| |
| Interface Index:: |
| The interface index specifies the network device the traffic object |
| is attached to. The function `rtnl_tc_set_link()` should be preferred |
| when setting the interface index. It stores the reference to the link |
| object in the tc object and allows retrieving the `mtu` and `linktype` |
| automatically. |
| + |
| [source,c] |
| ----- |
| void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex); |
| void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link); |
| int rtnl_tc_get_ifindex(struct rtnl_tc *tc); |
| ----- |
| |
| Link Type:: |
| The link type specifies the kind of link that is used by the network |
| device (e.g. ethernet, ATM, ...). It is derived automatically when |
| the network device is specified with `rtnl_tc_set_link()`. |
| The default fallback is `ARPHRD_ETHER` (ethernet). |
| + |
| [source,c] |
| ----- |
| void rtnl_tc_set_linktype(struct rtnl_tc *tc, uint32_t type); |
| uint32_t rtnl_tc_get_linktype(struct rtnl_tc *tc); |
| ----- |
| |
| Kind:: |
| The kind character string specifies the type of qdisc, class, |
| classifier. Setting the kind results in the module specific |
| structure being allocated. Therefore it is imperative to call |
| `rtnl_tc_set_kind()` before using any type specific API functions |
| such as `rtnl_htb_set_rate()`. |
| + |
| [source,c] |
| ----- |
| int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind); |
| char *rtnl_tc_get_kind(struct rtnl_tc *tc); |
| ----- |
| |
| MPU:: |
| The Minimum Packet Unit specifies the minimum packet size which will |
| be transmitted |
| ever be seen by this traffic control object. This value is used for |
| rate calculations. Not all object implementations will make use of |
| this value. The default value is 0. |
| + |
| [source,c] |
| ----- |
| void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu); |
| uint32_t rtnl_tc_get_mpu(struct rtnl_tc *tc); |
| ----- |
| |
| MTU:: |
| The Maximum Transmission Unit specifies the maximum packet size which |
| will be transmitted. The value is derived from the link specified |
| with `rtnl_tc_set_link()` if not overwritten with `rtnl_tc_set_mtu()`. |
| If no link and MTU is specified, the value defaults to 1500 |
| (ethernet). |
| + |
| [source,c] |
| ----- |
| void rtnl_tc_set_mtu(struct rtnl_tc *tc, uint32_t mtu); |
| uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc); |
| ----- |
| |
| Overhead:: |
| The overhead specifies the additional overhead per packet caused by |
| the network layer. This value can be used to correct packet size |
| calculations if the packet size on the wire does not match the packet |
| size seen by the kernel. The default value is 0. |
| + |
| [source,c] |
| ----- |
| void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead); |
| uint32_t rtnl_tc_get_overhead(struct rtnl_tc *tc); |
| ----- |
| |
| Parent:: |
| Specifies the parent traffic control object. The parent is identified |
| by its handle. Special values are: |
| - `TC_H_ROOT`: attach tc object directly to network device (root |
| qdisc, root classifier) |
| - `TC_H_INGRESS`: same as `TC_H_ROOT` but on the ingress side of the |
| network stack. |
| + |
| [source,c] |
| ----- |
| void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent); |
| uint32_t rtnl_tc_get_parent(struct rtnl_tc *tc); |
| ----- |
| |
| Statistics:: |
| Generic statistics, see <<tc_stats>> for additional information. |
| + |
| [source,c] |
| ----- |
| uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id); |
| ----- |
| |
| [[tc_stats]] |
| ==== Accessing Statistics |
| |
| The traffic control object holds a set of generic statistics. Not all |
| traffic control modules will make use of all of these statistics. Some |
| modules may provide additional statistics via their own APIs. |
| |
| .Statistic identifiers `(enum rtnl_tc_stat)` |
| [cols="m,,", options="header", frame="topbot"] |
| |==================================================================== |
| | ID | Type | Description |
| | RTNL_TC_PACKETS | Counter | Total # of packets transmitted |
| | RTNL_TC_BYTES | Counter | Total # of bytes transmitted |
| | RTNL_TC_RATE_BPS | Rate | Current bytes/s rate |
| | RTNL_TC_RATE_PPS | Rate | Current packets/s rate |
| | RTNL_TC_QLEN | Rate | Current length of the queue |
| | RTNL_TC_BACKLOG | Rate | # of packets currently backlogged |
| | RTNL_TC_DROPS | Counter | # of packets dropped |
| | RTNL_TC_REQUEUES | Counter | # of packets requeued |
| | RTNL_TC_OVERLIMITS | Counter | # of packets that exceeded the limit |
| |==================================================================== |
| |
| NOTE: `RTNL_TC_RATE_BPS` and `RTNL_TC_RATE_PPS` only return meaningful |
| values if a rate estimator has been configured. |
| |
| .Usage Example: Retrieving tc statistics |
| [source,c] |
| ------- |
| #include <netlink/route/tc.h> |
| |
| uint64_t drops, qlen; |
| |
| drops = rtnl_tc_get_stat(TC_CAST(qdisc), RTNL_TC_DROPS); |
| qlen = rtnl_tc_get_stat(TC_CAST(qdisc), RTNL_TC_QLEN); |
| ------- |
| |
| ==== Rate Table Calculations |
| TODO |
| |
| [[tc_qdisc]] |
| === Queueing Discipline (qdisc) |
| |
| .Classless Qdisc |
| |
| The queueing discipline (qdisc) is used to implement fair queueing, |
| prioritization or rate control. It provides a _enqueue()_ and |
| _dequeue()_ operation. Whenever a network packet leaves the networking |
| stack over a network device, be it a physical or virtual device, it |
| will be enqueued to a qdisc unless the device is queueless. The |
| _enqueue()_ operation is followed by an immediate call to _dequeue()_ |
| for the same qdisc to eventually retrieve a packet which can be |
| scheduled for transmission by the driver. Additionally, the networking |
| stack runs a watchdog which polls the qdisc regularly to dequeue and |
| send packets even if no new packets are being enqueued. |
| |
| This additional watchdog is required due to the fact that qdiscs may |
| hold on to packets and not return any packets upon _dequeue()_ in |
| order to enforce bandwidth restrictions. |
| |
| image:classless_qdisc_nbands.png[alt="Multiband Qdisc", float="right"] |
| |
| The figure illustrates a trivial example of a classless qdisc |
| consisting of three bands (queues). Use of multiple bands is a common |
| technique in qdiscs to implement fair queueing between flows or |
| prioritize differentiated services. |
| |
| Classless qdiscs can be regarded as a blackbox, their inner workings |
| can only be steered using the configuration parameters provided by the |
| qdisc. There is no way of taking influence on the structure of its |
| internal queues itself. |
| |
| .Classful Qdisc |
| |
| Classful qdiscs allow for the queueing structure and classification |
| process to be created by the user. |
| |
| image:classful_qdisc.png["Classful Qdisc"] |
| |
| The figure above shows a classful qdisc with a classifier attached to |
| it which will make the decision whether to enqueue a packet to traffic |
| class +1:1+ or +1:2+. Unlike with classless qdiscs, classful qdiscs |
| allow the classification process and the structure of the queues to be |
| defined by the user. This allows for complex traffic class rules to |
| be applied. |
| |
| .List of Qdisc Implementations |
| [options="header", frame="topbot", cols="2,1^,8"] |
| |====================================================================== |
| | Qdisc | Classful | Description |
| | ATM | Yes | FIXME |
| | Blackhole | No | This qdisc will drop all packets passed to it. |
| | CBQ | Yes | |
| The CBQ (Class Based Queueing) is a classful qdisc which allows |
| creating traffic classes and enforce bandwidth limitations for each |
| class. |
| | DRR | Yes | |
| The DRR (Deficit Round Robin) scheduler is a classful qdisc |
| implementing fair queueing. Each class is assigned a quantum specifying |
| the maximum number of bytes that can be served per round. Unused |
| quantum at the end of the round is carried over to the next round. |
| | DSMARK | Yes | FIXME |
| | FIFO | No | FIXME |
| | GRED | No | FIXME |
| | HFSC | Yes | FIXME |
| | HTB | Yes | FIXME |
| | mq | Yes | FIXME |
| | multiq | Yes | FIXME |
| | netem | No | FIXME |
| | Prio | Yes | FIXME |
| | RED | Yes | FIXME |
| | SFQ | Yes | FIXME |
| | TBF | Yes | FIXME |
| | teql | No | FIXME |
| |====================================================================== |
| |
| |
| .QDisc API Overview |
| [cols="a,a", options="header", frame="topbot"] |
| |==================================================================== |
| | Attribute | C Interface |
| | |
| Allocation / Freeing:: |
| | |
| [source,c] |
| ----- |
| struct rtnl_qdisc *rtnl_qdisc_alloc(void); |
| void rtnl_qdisc_put(struct rtnl_qdisc *qdisc); |
| ----- |
| | |
| Addition:: |
| | |
| [source,c] |
| ----- |
| int rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, int flags, |
| struct nl_msg **result); |
| int rtnl_qdisc_add(struct nl_sock *sock, struct rtnl_qdisc *qdisc, |
| int flags); |
| ----- |
| | |
| Modification:: |
| | |
| [source,c] |
| ----- |
| int rtnl_qdisc_build_change_request(struct rtnl_qdisc *old, |
| struct rtnl_qdisc *new, |
| struct nl_msg **result); |
| int rtnl_qdisc_change(struct nl_sock *sock, struct rtnl_qdisc *old, |
| struct rtnl_qdisc *new); |
| ----- |
| | |
| Deletion:: |
| | |
| [source,c] |
| ----- |
| int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc, |
| struct nl_msg **result); |
| int rtnl_qdisc_delete(struct nl_sock *sock, struct rtnl_qdisc *qdisc); |
| ----- |
| | |
| Cache:: |
| | |
| [source,c] |
| ----- |
| int rtnl_qdisc_alloc_cache(struct nl_sock *sock, |
| struct nl_cache **cache); |
| struct rtnl_qdisc *rtnl_qdisc_get(struct nl_cache *cache, int, uint32_t); |
| |
| struct rtnl_qdisc *rtnl_qdisc_get_by_parent(struct nl_cache *, int, uint32_t); |
| ----- |
| |==================================================================== |
| |
| [[qdisc_get]] |
| ==== Retrieving Qdisc Configuration |
| |
| The function rtnl_qdisc_alloc_cache() is used to retrieve the current |
| qdisc configuration in the kernel. It will construct a +RTM_GETQDISC+ |
| netlink message, requesting the complete list of qdiscs configured in |
| the kernel. |
| |
| [source,c] |
| ------- |
| #include <netlink/route/qdisc.h> |
| |
| struct nl_cache *all_qdiscs; |
| |
| if (rtnl_link_alloc_cache(sock, &all_qdiscs) < 0) |
| /* error while retrieving qdisc cfg */ |
| ------- |
| |
| The cache can be accessed using the following functions: |
| |
| - Search qdisc with matching ifindex and handle: |
| + |
| [source,c] |
| -------- |
| struct rtnl_qdisc *rtnl_qdisc_get(struct nl_cache *cache, int ifindex, uint32_t handle); |
| -------- |
| - Search qdisc with matching ifindex and parent: |
| + |
| [source,c] |
| -------- |
| struct rtnl_qdisc *rtnl_qdisc_get_by_parent(struct nl_cache *cache, int ifindex , uint32_t parent); |
| -------- |
| - Or any of the generic cache functions (e.g. nl_cache_search(), nl_cache_dump(), etc.) |
| |
| .Example: Search and print qdisc |
| [source,c] |
| ------- |
| struct rtnl_qdisc *qdisc; |
| int ifindex; |
| |
| ifindex = rtnl_link_get_ifindex(eth0_obj); |
| |
| /* search for qdisc on eth0 with handle 1:0 */ |
| if (!(qdisc = rtnl_qdisc_get(all_qdiscs, ifindex, TC_HANDLE(1, 0)))) |
| /* no such qdisc found */ |
| |
| nl_object_dump(OBJ_CAST(qdisc), NULL); |
| |
| rtnl_qdisc_put(qdisc); |
| ------- |
| |
| [[qdisc_add]] |
| ==== Adding a Qdisc |
| |
| In order to add a new qdisc to the kernel, a qdisc object needs to be |
| allocated. It will hold all attributes of the new qdisc. |
| |
| [source,c] |
| ----- |
| #include <netlink/route/qdisc.h> |
| |
| struct rtnl_qdisc *qdisc; |
| |
| if (!(qdisc = rtnl_qdisc_alloc())) |
| /* OOM error */ |
| ----- |
| |
| The next step is to specify all generic qdisc attributes using the tc |
| object interface described in the section <<tc_attr>>. |
| |
| The following attributes must be specified: |
| - IfIndex |
| - Parent |
| - Kind |
| |
| [source,c] |
| ----- |
| /* Attach qdisc to device eth0 */ |
| rtnl_tc_set_link(TC_CAST(qdisc), eth0_obj); |
| |
| /* Make this the root qdisc */ |
| rtnl_tc_set_parent(TC_CAST(qdisc), TC_H_ROOT); |
| |
| /* Set qdisc identifier to 1:0, if left unspecified, a handle will be generated by the kernel. */ |
| rtnl_tc_set_handle(TC_CAST(qdisc), TC_HANDLE(1, 0)); |
| |
| /* Make this a HTB qdisc */ |
| rtnl_tc_set_kind(TC_CAST(qdisc), "htb"); |
| ----- |
| |
| After specifying the qdisc kind (rtnl_tc_set_kind()) the qdisc type |
| specific interface can be used to set attributes which are specific |
| to the respective qdisc implementations: |
| |
| [source,c] |
| ------ |
| /* HTB feature: Make unclassified packets go to traffic class 1:5 */ |
| rtnl_htb_set_defcls(qdisc, TC_HANDLE(1, 5)); |
| ------ |
| |
| Finally, the qdisc is ready to be added and can be passed on to the |
| function rntl_qdisc_add() which takes care of constructing a netlink |
| message requesting the addition of the new qdisc, sends the message to |
| the kernel and waits for the response by the kernel. The function |
| returns 0 if the qdisc has been added or updated successfully or a |
| negative error code if an error occured. |
| |
| CAUTION: The kernel operation for updating and adding a qdisc is the |
| same. Therefore when calling rtnl_qdisc_add() any existing |
| qdisc with matching handle will be updated unless the flag |
| NLM_F_EXCL is specified. |
| |
| The following flags may be specified: |
| [horizontal] |
| NLM_F_CREATE:: Create qdisc if it does not exist, otherwise |
| -NLE_OBJ_NOTFOUND is returned. |
| NLM_F_REPLACE:: If another qdisc is already attached to the same |
| parent and their handles mismatch, replace the qdisc |
| instead of returning -EEXIST. |
| NLM_F_EXCL:: Return -NLE_EXISTS if a qdisc with matching handles |
| exists already. |
| |
| WARNING: The function rtnl_qdisc_add() requires administrator |
| privileges. |
| |
| [source,c] |
| ------ |
| /* Submit request to kernel and wait for response */ |
| err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE); |
| |
| /* Return the qdisc object to free memory resources */ |
| rtnl_qdisc_put(qdisc); |
| |
| if (err < 0) { |
| fprintf(stderr, "Unable to add qdisc: %s\n", nl_geterror(err)); |
| return err; |
| } |
| ------ |
| |
| ==== Deleting a qdisc |
| |
| [source,c] |
| ------ |
| #include <netlink/route/qdisc.h> |
| |
| struct rtnl_qdisc *qdisc; |
| |
| qdisc = rtnl_qdisc_alloc(); |
| |
| rtnl_tc_set_link(TC_CAST(qdisc), eth0_obj); |
| rtnl_tc_set_parent(TC_CAST(qdisc), TC_H_ROOT); |
| |
| rtnl_qdisc_delete(sock, qdisc) |
| |
| rtnl_qdisc_put(qdisc); |
| ------ |
| |
| WARNING: The function rtnl_qdisc_delete() requires administrator |
| privileges. |
| |
| |
| [[qdisc_htb]] |
| ==== HTB - Hierarchical Token Bucket |
| |
| .HTB Qdisc Attributes |
| |
| Default Class:: |
| The default class is the fallback class to which all traffic which |
| remained unclassified is directed to. If no default class or an |
| invalid default class is specified, packets are transmitted directly |
| to the next layer (direct transmissions). |
| + |
| [source,c] |
| ----- |
| uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc); |
| int rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls); |
| ----- |
| |
| Rate to Quantum (r2q):: |
| TODO |
| + |
| [source,c] |
| ----- |
| uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc); |
| int rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum); |
| ----- |
| |
| |
| .HTB Class Attributes |
| |
| Priority:: |
| + |
| [source,c] |
| ----- |
| uint32_t rtnl_htb_get_prio(struct rtnl_class *class); |
| int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio); |
| ----- |
| |
| Rate:: |
| The rate (bytes/s) specifies the maximum bandwidth an individual class |
| can use without borrowing. The rate of a class should always be greater |
| or erqual than the rate of its children. |
| + |
| [source,c] |
| ----- |
| uint32_t rtnl_htb_get_rate(struct rtnl_class *class); |
| int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t ceil); |
| ----- |
| |
| Ceil Rate:: |
| The ceil rate specifies the maximum bandwidth an individual class |
| can use. This includes bandwidth that is being borrowed from other |
| classes. Ceil defaults to the class rate implying that by default |
| the class will not borrow. The ceil rate of a class should always |
| be greater or erqual than the ceil rate of its children. |
| + |
| [source,c] |
| ----- |
| uint32_t rtnl_htb_get_ceil(struct rtnl_class *class); |
| int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil); |
| ----- |
| |
| Burst:: |
| TODO |
| + |
| [source,c] |
| ----- |
| uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class); |
| int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t burst); |
| ----- |
| |
| Ceil Burst:: |
| TODO |
| + |
| [source,c] |
| ----- |
| uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *); |
| int rtnl_htb_set_cbuffer(struct rtnl_class *, uint32_t); |
| ----- |
| |
| Quantum:: |
| TODO |
| + |
| [source,c] |
| ----- |
| uint32_t rtnl_htb_get_quantum(struct rtnl_class *class); |
| int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum); |
| ----- |
| |
| |
| [[tc_class]] |
| === Class |
| |
| [options="header", cols="s,a,a,a,a"] |
| |======================================================================= |
| | | UNSPEC | TC_H_ROOT | 0:pY | pX:pY |
| | UNSPEC 3+^| |
| [horizontal] |
| qdisc =:: root-qdisc |
| class =:: root-qdisc:0 |
| | |
| [horizontal] |
| qdisc =:: pX:0 |
| class =:: pX:0 |
| | 0:hY 3+^| |
| [horizontal] |
| qdisc =:: root-qdisc |
| class =:: root-qdisc:hY |
| | |
| [horizontal] |
| qdisc =:: pX:0 |
| class =:: pX:hY |
| | hX:hY 3+^| |
| [horizontal] |
| qdisc =:: hX: |
| class =:: hX:hY |
| | |
| if pX != hX |
| return -EINVAL |
| [horizontal] |
| qdisc =:: hX: |
| class =:: hX:hY |
| |======================================================================= |
| |
| [[tc_cls]] |
| === Classifier (cls) |
| |
| TODO |
| |
| [[tc_classid_mngt]] |
| === ClassID Management |
| |
| TODO |
| |
| [[tc_pktloc]] |
| === Packet Location Aliasing (pktloc) |
| |
| TODO |
| |
| [[tc_api]] |
| === Traffic Control Module API |
| |
| TODO |