1780 lines
39 KiB
C
1780 lines
39 KiB
C
// SPDX-License-Identifier: ISC
|
|
/*
|
|
* Copyright (c) 2018 Rafael Zalamena
|
|
*/
|
|
|
|
#include <zebra.h>
|
|
|
|
#if defined(HAVE_NETLINK) && defined(NETLINK_DEBUG)
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <linux/netconf.h>
|
|
#include <linux/netlink.h>
|
|
#include <linux/nexthop.h>
|
|
#include <linux/rtnetlink.h>
|
|
#include <net/if_arp.h>
|
|
#include <linux/fib_rules.h>
|
|
#include <linux/lwtunnel.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
|
|
#include "zebra/rt_netlink.h"
|
|
#include "zebra/kernel_netlink.h"
|
|
#include "lib/vxlan.h"
|
|
|
|
const char *nlmsg_type2str(uint16_t type)
|
|
{
|
|
switch (type) {
|
|
/* Generic */
|
|
case NLMSG_NOOP:
|
|
return "NOOP";
|
|
case NLMSG_ERROR:
|
|
return "ERROR";
|
|
case NLMSG_DONE:
|
|
return "DONE";
|
|
case NLMSG_OVERRUN:
|
|
return "OVERRUN";
|
|
|
|
/* RTM */
|
|
case RTM_NEWLINK:
|
|
return "NEWLINK";
|
|
case RTM_DELLINK:
|
|
return "DELLINK";
|
|
case RTM_GETLINK:
|
|
return "GETLINK";
|
|
case RTM_SETLINK:
|
|
return "SETLINK";
|
|
|
|
case RTM_NEWADDR:
|
|
return "NEWADDR";
|
|
case RTM_DELADDR:
|
|
return "DELADDR";
|
|
case RTM_GETADDR:
|
|
return "GETADDR";
|
|
|
|
case RTM_NEWROUTE:
|
|
return "NEWROUTE";
|
|
case RTM_DELROUTE:
|
|
return "DELROUTE";
|
|
case RTM_GETROUTE:
|
|
return "GETROUTE";
|
|
|
|
case RTM_NEWNEIGH:
|
|
return "NEWNEIGH";
|
|
case RTM_DELNEIGH:
|
|
return "DELNEIGH";
|
|
case RTM_GETNEIGH:
|
|
return "GETNEIGH";
|
|
|
|
case RTM_NEWRULE:
|
|
return "NEWRULE";
|
|
case RTM_DELRULE:
|
|
return "DELRULE";
|
|
case RTM_GETRULE:
|
|
return "GETRULE";
|
|
|
|
case RTM_NEWNEXTHOP:
|
|
return "NEWNEXTHOP";
|
|
case RTM_DELNEXTHOP:
|
|
return "DELNEXTHOP";
|
|
case RTM_GETNEXTHOP:
|
|
return "GETNEXTHOP";
|
|
|
|
case RTM_NEWTUNNEL:
|
|
return "NEWTUNNEL";
|
|
case RTM_DELTUNNEL:
|
|
return "DELTUNNEL";
|
|
case RTM_GETTUNNEL:
|
|
return "GETTUNNEL";
|
|
|
|
case RTM_NEWNETCONF:
|
|
return "RTM_NEWNETCONF";
|
|
case RTM_DELNETCONF:
|
|
return "RTM_DELNETCONF";
|
|
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *af_type2str(int type)
|
|
{
|
|
switch (type) {
|
|
case AF_UNSPEC:
|
|
return "AF_UNSPEC";
|
|
case AF_UNIX:
|
|
return "AF_UNIX";
|
|
case AF_INET:
|
|
return "AF_INET";
|
|
case AF_INET6:
|
|
return "AF_INET6";
|
|
case AF_BRIDGE:
|
|
return "AF_BRIDGE";
|
|
case AF_NETLINK:
|
|
return "AF_NETLINK";
|
|
#ifdef AF_MPLS
|
|
case AF_MPLS:
|
|
return "AF_MPLS";
|
|
#endif /* AF_MPLS */
|
|
case AF_BLUETOOTH:
|
|
return "AF_BLUETOOTH";
|
|
case AF_VSOCK:
|
|
return "AF_VSOCK";
|
|
case AF_KEY:
|
|
return "AF_KEY";
|
|
case AF_PACKET:
|
|
return "AF_PACKET";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *ifi_type2str(int type)
|
|
{
|
|
switch (type) {
|
|
case ARPHRD_ETHER:
|
|
return "ETHER";
|
|
case ARPHRD_EETHER:
|
|
return "EETHER";
|
|
case ARPHRD_NETROM:
|
|
return "NETROM";
|
|
case ARPHRD_AX25:
|
|
return "AX25";
|
|
case ARPHRD_PRONET:
|
|
return "PRONET";
|
|
case ARPHRD_CHAOS:
|
|
return "CHAOS";
|
|
case ARPHRD_IEEE802:
|
|
return "IEEE802";
|
|
case ARPHRD_ARCNET:
|
|
return "ARCNET";
|
|
case ARPHRD_APPLETLK:
|
|
return "APPLETLK";
|
|
case ARPHRD_DLCI:
|
|
return "DLCI";
|
|
case ARPHRD_ATM:
|
|
return "ATM";
|
|
case ARPHRD_METRICOM:
|
|
return "METRICOM";
|
|
case ARPHRD_IEEE1394:
|
|
return "IEEE1394";
|
|
case ARPHRD_EUI64:
|
|
return "EUI64";
|
|
case ARPHRD_INFINIBAND:
|
|
return "INFINIBAND";
|
|
case ARPHRD_SLIP:
|
|
return "SLIP";
|
|
case ARPHRD_CSLIP:
|
|
return "CSLIP";
|
|
case ARPHRD_SLIP6:
|
|
return "SLIP6";
|
|
case ARPHRD_CSLIP6:
|
|
return "CSLIP6";
|
|
case ARPHRD_RSRVD:
|
|
return "RSRVD";
|
|
case ARPHRD_ADAPT:
|
|
return "ADAPT";
|
|
case ARPHRD_ROSE:
|
|
return "ROSE";
|
|
case ARPHRD_X25:
|
|
return "X25";
|
|
case ARPHRD_PPP:
|
|
return "PPP";
|
|
case ARPHRD_HDLC:
|
|
return "HDLC";
|
|
case ARPHRD_LAPB:
|
|
return "LAPB";
|
|
case ARPHRD_DDCMP:
|
|
return "DDCMP";
|
|
case ARPHRD_RAWHDLC:
|
|
return "RAWHDLC";
|
|
case ARPHRD_TUNNEL:
|
|
return "TUNNEL";
|
|
case ARPHRD_TUNNEL6:
|
|
return "TUNNEL6";
|
|
case ARPHRD_FRAD:
|
|
return "FRAD";
|
|
case ARPHRD_SKIP:
|
|
return "SKIP";
|
|
case ARPHRD_LOOPBACK:
|
|
return "LOOPBACK";
|
|
case ARPHRD_LOCALTLK:
|
|
return "LOCALTLK";
|
|
case ARPHRD_FDDI:
|
|
return "FDDI";
|
|
case ARPHRD_BIF:
|
|
return "BIF";
|
|
case ARPHRD_SIT:
|
|
return "SIT";
|
|
case ARPHRD_IPDDP:
|
|
return "IPDDP";
|
|
case ARPHRD_IPGRE:
|
|
return "IPGRE";
|
|
case ARPHRD_PIMREG:
|
|
return "PIMREG";
|
|
case ARPHRD_HIPPI:
|
|
return "HIPPI";
|
|
case ARPHRD_ASH:
|
|
return "ASH";
|
|
case ARPHRD_ECONET:
|
|
return "ECONET";
|
|
case ARPHRD_IRDA:
|
|
return "IRDA";
|
|
case ARPHRD_FCPP:
|
|
return "FCPP";
|
|
case ARPHRD_FCAL:
|
|
return "FCAL";
|
|
case ARPHRD_FCPL:
|
|
return "FCPL";
|
|
case ARPHRD_FCFABRIC:
|
|
return "FCFABRIC";
|
|
case ARPHRD_IEEE802_TR:
|
|
return "IEEE802_TR";
|
|
case ARPHRD_IEEE80211:
|
|
return "IEEE80211";
|
|
case ARPHRD_IEEE80211_PRISM:
|
|
return "IEEE80211_PRISM";
|
|
case ARPHRD_IEEE80211_RADIOTAP:
|
|
return "IEEE80211_RADIOTAP";
|
|
case ARPHRD_IEEE802154:
|
|
return "IEEE802154";
|
|
#ifdef ARPHRD_VSOCKMON
|
|
case ARPHRD_VSOCKMON:
|
|
return "VSOCKMON";
|
|
#endif /* ARPHRD_VSOCKMON */
|
|
case ARPHRD_VOID:
|
|
return "VOID";
|
|
case ARPHRD_NONE:
|
|
return "NONE";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *ifla_pdr_type2str(int type)
|
|
{
|
|
switch (type) {
|
|
case IFLA_PROTO_DOWN_REASON_UNSPEC:
|
|
return "UNSPEC";
|
|
case IFLA_PROTO_DOWN_REASON_MASK:
|
|
return "MASK";
|
|
case IFLA_PROTO_DOWN_REASON_VALUE:
|
|
return "VALUE";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *ifla_info_type2str(int type)
|
|
{
|
|
switch (type) {
|
|
case IFLA_INFO_UNSPEC:
|
|
return "UNSPEC";
|
|
case IFLA_INFO_KIND:
|
|
return "KIND";
|
|
case IFLA_INFO_DATA:
|
|
return "DATA";
|
|
case IFLA_INFO_XSTATS:
|
|
return "XSTATS";
|
|
case IFLA_INFO_SLAVE_KIND:
|
|
return "SLAVE_KIND";
|
|
case IFLA_INFO_SLAVE_DATA:
|
|
return "SLAVE_DATA";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *rta_type2str(int type)
|
|
{
|
|
switch (type) {
|
|
case IFLA_UNSPEC:
|
|
return "UNSPEC";
|
|
case IFLA_ADDRESS:
|
|
return "ADDRESS";
|
|
case IFLA_BROADCAST:
|
|
return "BROADCAST";
|
|
case IFLA_IFNAME:
|
|
return "IFNAME";
|
|
case IFLA_MTU:
|
|
return "MTU";
|
|
case IFLA_LINK:
|
|
return "LINK";
|
|
case IFLA_QDISC:
|
|
return "QDISC";
|
|
case IFLA_STATS:
|
|
return "STATS";
|
|
case IFLA_COST:
|
|
return "COST";
|
|
case IFLA_PRIORITY:
|
|
return "PRIORITY";
|
|
case IFLA_MASTER:
|
|
return "MASTER";
|
|
case IFLA_WIRELESS:
|
|
return "WIRELESS";
|
|
case IFLA_PROTINFO:
|
|
return "PROTINFO";
|
|
case IFLA_TXQLEN:
|
|
return "TXQLEN";
|
|
case IFLA_MAP:
|
|
return "MAP";
|
|
case IFLA_WEIGHT:
|
|
return "WEIGHT";
|
|
case IFLA_OPERSTATE:
|
|
return "OPERSTATE";
|
|
case IFLA_LINKMODE:
|
|
return "LINKMODE";
|
|
case IFLA_LINKINFO:
|
|
return "LINKINFO";
|
|
case IFLA_NET_NS_PID:
|
|
return "NET_NS_PID";
|
|
case IFLA_IFALIAS:
|
|
return "IFALIAS";
|
|
case IFLA_NUM_VF:
|
|
return "NUM_VF";
|
|
case IFLA_VFINFO_LIST:
|
|
return "VFINFO_LIST";
|
|
case IFLA_STATS64:
|
|
return "STATS64";
|
|
case IFLA_VF_PORTS:
|
|
return "VF_PORTS";
|
|
case IFLA_PORT_SELF:
|
|
return "PORT_SELF";
|
|
case IFLA_AF_SPEC:
|
|
return "AF_SPEC";
|
|
case IFLA_GROUP:
|
|
return "GROUP";
|
|
case IFLA_NET_NS_FD:
|
|
return "NET_NS_FD";
|
|
case IFLA_EXT_MASK:
|
|
return "EXT_MASK";
|
|
case IFLA_PROMISCUITY:
|
|
return "PROMISCUITY";
|
|
case IFLA_NUM_TX_QUEUES:
|
|
return "NUM_TX_QUEUES";
|
|
case IFLA_NUM_RX_QUEUES:
|
|
return "NUM_RX_QUEUES";
|
|
case IFLA_CARRIER:
|
|
return "CARRIER";
|
|
case IFLA_PHYS_PORT_ID:
|
|
return "PHYS_PORT_ID";
|
|
case IFLA_CARRIER_CHANGES:
|
|
return "CARRIER_CHANGES";
|
|
case IFLA_PHYS_SWITCH_ID:
|
|
return "PHYS_SWITCH_ID";
|
|
case IFLA_LINK_NETNSID:
|
|
return "LINK_NETNSID";
|
|
case IFLA_PHYS_PORT_NAME:
|
|
return "PHYS_PORT_NAME";
|
|
case IFLA_PROTO_DOWN:
|
|
return "PROTO_DOWN";
|
|
#ifdef IFLA_GSO_MAX_SEGS
|
|
case IFLA_GSO_MAX_SEGS:
|
|
return "GSO_MAX_SEGS";
|
|
#endif /* IFLA_GSO_MAX_SEGS */
|
|
#ifdef IFLA_GSO_MAX_SIZE
|
|
case IFLA_GSO_MAX_SIZE:
|
|
return "GSO_MAX_SIZE";
|
|
#endif /* IFLA_GSO_MAX_SIZE */
|
|
#ifdef IFLA_PAD
|
|
case IFLA_PAD:
|
|
return "PAD";
|
|
#endif /* IFLA_PAD */
|
|
#ifdef IFLA_XDP
|
|
case IFLA_XDP:
|
|
return "XDP";
|
|
#endif /* IFLA_XDP */
|
|
#ifdef IFLA_EVENT
|
|
case IFLA_EVENT:
|
|
return "EVENT";
|
|
#endif /* IFLA_EVENT */
|
|
case IFLA_PROTO_DOWN_REASON:
|
|
return "PROTO_DOWN_REASON";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *rtm_type2str(int type)
|
|
{
|
|
switch (type) {
|
|
case RTN_UNSPEC:
|
|
return "UNSPEC";
|
|
case RTN_UNICAST:
|
|
return "UNICAST";
|
|
case RTN_LOCAL:
|
|
return "LOCAL";
|
|
case RTN_BROADCAST:
|
|
return "BROADCAST";
|
|
case RTN_ANYCAST:
|
|
return "ANYCAST";
|
|
case RTN_MULTICAST:
|
|
return "MULTICAST";
|
|
case RTN_BLACKHOLE:
|
|
return "BLACKHOLE";
|
|
case RTN_UNREACHABLE:
|
|
return "UNREACHABLE";
|
|
case RTN_PROHIBIT:
|
|
return "PROHIBIT";
|
|
case RTN_THROW:
|
|
return "THROW";
|
|
case RTN_NAT:
|
|
return "NAT";
|
|
case RTN_XRESOLVE:
|
|
return "XRESOLVE";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *rtm_protocol2str(int type)
|
|
{
|
|
switch (type) {
|
|
case RTPROT_UNSPEC:
|
|
return "UNSPEC";
|
|
case RTPROT_REDIRECT:
|
|
return "REDIRECT";
|
|
case RTPROT_KERNEL:
|
|
return "KERNEL";
|
|
case RTPROT_BOOT:
|
|
return "BOOT";
|
|
case RTPROT_STATIC:
|
|
return "STATIC";
|
|
case RTPROT_GATED:
|
|
return "GATED";
|
|
case RTPROT_RA:
|
|
return "RA";
|
|
case RTPROT_MRT:
|
|
return "MRT";
|
|
case RTPROT_ZEBRA:
|
|
return "ZEBRA";
|
|
case RTPROT_BGP:
|
|
return "BGP";
|
|
case RTPROT_ISIS:
|
|
return "ISIS";
|
|
case RTPROT_OSPF:
|
|
return "OSPF";
|
|
case RTPROT_BIRD:
|
|
return "BIRD";
|
|
case RTPROT_DNROUTED:
|
|
return "DNROUTED";
|
|
case RTPROT_XORP:
|
|
return "XORP";
|
|
case RTPROT_NTK:
|
|
return "NTK";
|
|
case RTPROT_DHCP:
|
|
return "DHCP";
|
|
case RTPROT_MROUTED:
|
|
return "MROUTED";
|
|
case RTPROT_BABEL:
|
|
return "BABEL";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *rtm_scope2str(int type)
|
|
{
|
|
switch (type) {
|
|
case RT_SCOPE_UNIVERSE:
|
|
return "UNIVERSE";
|
|
case RT_SCOPE_SITE:
|
|
return "SITE";
|
|
case RT_SCOPE_LINK:
|
|
return "LINK";
|
|
case RT_SCOPE_HOST:
|
|
return "HOST";
|
|
case RT_SCOPE_NOWHERE:
|
|
return "NOWHERE";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *rtm_rta2str(int type)
|
|
{
|
|
switch (type) {
|
|
case RTA_UNSPEC:
|
|
return "UNSPEC";
|
|
case RTA_DST:
|
|
return "DST";
|
|
case RTA_SRC:
|
|
return "SRC";
|
|
case RTA_IIF:
|
|
return "IIF";
|
|
case RTA_OIF:
|
|
return "OIF";
|
|
case RTA_GATEWAY:
|
|
return "GATEWAY";
|
|
case RTA_PRIORITY:
|
|
return "PRIORITY";
|
|
case RTA_PREF:
|
|
return "PREF";
|
|
case RTA_PREFSRC:
|
|
return "PREFSRC";
|
|
case RTA_MARK:
|
|
return "MARK";
|
|
case RTA_METRICS:
|
|
return "METRICS";
|
|
case RTA_MULTIPATH:
|
|
return "MULTIPATH";
|
|
case RTA_PROTOINFO:
|
|
return "PROTOINFO";
|
|
case RTA_FLOW:
|
|
return "FLOW";
|
|
case RTA_CACHEINFO:
|
|
return "CACHEINFO";
|
|
case RTA_TABLE:
|
|
return "TABLE";
|
|
case RTA_MFC_STATS:
|
|
return "MFC_STATS";
|
|
case RTA_NH_ID:
|
|
return "NH_ID";
|
|
case RTA_EXPIRES:
|
|
return "EXPIRES";
|
|
case RTA_VIA:
|
|
return "VIA";
|
|
case RTA_ENCAP_TYPE:
|
|
return "RTA_ENCAP_TYPE";
|
|
case RTA_ENCAP:
|
|
return "RTA_ENCAP";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *neigh_rta2str(int type)
|
|
{
|
|
switch (type) {
|
|
case NDA_UNSPEC:
|
|
return "UNSPEC";
|
|
case NDA_DST:
|
|
return "DST";
|
|
case NDA_LLADDR:
|
|
return "LLADDR";
|
|
case NDA_CACHEINFO:
|
|
return "CACHEINFO";
|
|
case NDA_PROBES:
|
|
return "PROBES";
|
|
case NDA_VLAN:
|
|
return "VLAN";
|
|
case NDA_PORT:
|
|
return "PORT";
|
|
case NDA_VNI:
|
|
return "VNI";
|
|
case NDA_IFINDEX:
|
|
return "IFINDEX";
|
|
case NDA_MASTER:
|
|
return "MASTER";
|
|
case NDA_LINK_NETNSID:
|
|
return "LINK_NETNSID";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *ifa_rta2str(int type)
|
|
{
|
|
switch (type) {
|
|
case IFA_UNSPEC:
|
|
return "UNSPEC";
|
|
case IFA_ADDRESS:
|
|
return "ADDRESS";
|
|
case IFA_LOCAL:
|
|
return "LOCAL";
|
|
case IFA_LABEL:
|
|
return "LABEL";
|
|
case IFA_BROADCAST:
|
|
return "BROADCAST";
|
|
case IFA_ANYCAST:
|
|
return "ANYCAST";
|
|
case IFA_CACHEINFO:
|
|
return "CACHEINFO";
|
|
case IFA_MULTICAST:
|
|
return "MULTICAST";
|
|
case IFA_FLAGS:
|
|
return "FLAGS";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *nhm_rta2str(int type)
|
|
{
|
|
switch (type) {
|
|
case NHA_UNSPEC:
|
|
return "UNSPEC";
|
|
case NHA_ID:
|
|
return "ID";
|
|
case NHA_GROUP:
|
|
return "GROUP";
|
|
case NHA_GROUP_TYPE:
|
|
return "GROUP_TYPE";
|
|
case NHA_BLACKHOLE:
|
|
return "BLACKHOLE";
|
|
case NHA_OIF:
|
|
return "OIF";
|
|
case NHA_GATEWAY:
|
|
return "GATEWAY";
|
|
case NHA_ENCAP_TYPE:
|
|
return "ENCAP_TYPE";
|
|
case NHA_ENCAP:
|
|
return "ENCAP";
|
|
case NHA_GROUPS:
|
|
return "GROUPS";
|
|
case NHA_MASTER:
|
|
return "MASTER";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *frh_rta2str(int type)
|
|
{
|
|
switch (type) {
|
|
case FRA_DST:
|
|
return "DST";
|
|
case FRA_SRC:
|
|
return "SRC";
|
|
case FRA_IIFNAME:
|
|
return "IIFNAME";
|
|
case FRA_GOTO:
|
|
return "GOTO";
|
|
case FRA_UNUSED2:
|
|
return "UNUSED2";
|
|
case FRA_PRIORITY:
|
|
return "PRIORITY";
|
|
case FRA_UNUSED3:
|
|
return "UNUSED3";
|
|
case FRA_UNUSED4:
|
|
return "UNUSED4";
|
|
case FRA_UNUSED5:
|
|
return "UNUSED5";
|
|
case FRA_FWMARK:
|
|
return "FWMARK";
|
|
case FRA_FLOW:
|
|
return "FLOW";
|
|
case FRA_TUN_ID:
|
|
return "TUN_ID";
|
|
case FRA_SUPPRESS_IFGROUP:
|
|
return "SUPPRESS_IFGROUP";
|
|
case FRA_SUPPRESS_PREFIXLEN:
|
|
return "SUPPRESS_PREFIXLEN";
|
|
case FRA_TABLE:
|
|
return "TABLE";
|
|
case FRA_FWMASK:
|
|
return "FWMASK";
|
|
case FRA_OIFNAME:
|
|
return "OIFNAME";
|
|
case FRA_PAD:
|
|
return "PAD";
|
|
case FRA_L3MDEV:
|
|
return "L3MDEV";
|
|
case FRA_UID_RANGE:
|
|
return "UID_RANGE";
|
|
case FRA_PROTOCOL:
|
|
return "PROTOCOL";
|
|
case FRA_IP_PROTO:
|
|
return "IP_PROTO";
|
|
case FRA_SPORT_RANGE:
|
|
return "SPORT_RANGE";
|
|
case FRA_DPORT_RANGE:
|
|
return "DPORT_RANGE";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
const char *frh_action2str(uint8_t action)
|
|
{
|
|
switch (action) {
|
|
case FR_ACT_TO_TBL:
|
|
return "TO_TBL";
|
|
case FR_ACT_GOTO:
|
|
return "GOTO";
|
|
case FR_ACT_NOP:
|
|
return "NOP";
|
|
case FR_ACT_RES3:
|
|
return "RES3";
|
|
case FR_ACT_RES4:
|
|
return "RES4";
|
|
case FR_ACT_BLACKHOLE:
|
|
return "BLACKHOLE";
|
|
case FR_ACT_UNREACHABLE:
|
|
return "UNREACHABLE";
|
|
case FR_ACT_PROHIBIT:
|
|
return "PROHIBIT";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
static const char *ncm_rta2str(int type)
|
|
{
|
|
switch (type) {
|
|
case NETCONFA_UNSPEC:
|
|
return "UNSPEC";
|
|
case NETCONFA_IFINDEX:
|
|
return "IFINDEX";
|
|
case NETCONFA_FORWARDING:
|
|
return "FORWARDING";
|
|
case NETCONFA_RP_FILTER:
|
|
return "RP_FILTER";
|
|
case NETCONFA_MC_FORWARDING:
|
|
return "MCAST";
|
|
case NETCONFA_PROXY_NEIGH:
|
|
return "PROXY_NEIGH";
|
|
case NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN:
|
|
return "IGNORE_LINKDOWN";
|
|
case NETCONFA_INPUT:
|
|
return "MPLS";
|
|
case NETCONFA_BC_FORWARDING:
|
|
return "BCAST";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
static void dump_on_off(uint32_t ival, const char *prefix)
|
|
{
|
|
zlog_debug("%s%s", prefix, (ival != 0) ? "on" : "off");
|
|
}
|
|
|
|
static inline void flag_write(int flags, int flag, const char *flagstr,
|
|
char *buf, size_t buflen)
|
|
{
|
|
if (CHECK_FLAG(flags, flag) == 0)
|
|
return;
|
|
|
|
if (buf[0])
|
|
strlcat(buf, ",", buflen);
|
|
|
|
strlcat(buf, flagstr, buflen);
|
|
}
|
|
|
|
const char *nlmsg_flags2str(uint16_t flags, char *buf, size_t buflen)
|
|
{
|
|
const char *bufp = buf;
|
|
|
|
*buf = 0;
|
|
/* Specific flags. */
|
|
flag_write(flags, NLM_F_REQUEST, "REQUEST", buf, buflen);
|
|
flag_write(flags, NLM_F_MULTI, "MULTI", buf, buflen);
|
|
flag_write(flags, NLM_F_ACK, "ACK", buf, buflen);
|
|
flag_write(flags, NLM_F_ECHO, "ECHO", buf, buflen);
|
|
flag_write(flags, NLM_F_DUMP, "DUMP", buf, buflen);
|
|
|
|
/* Netlink family type dependent. */
|
|
flag_write(flags, 0x0100, "(ROOT|REPLACE|CAPPED)", buf, buflen);
|
|
flag_write(flags, 0x0200, "(MATCH|EXCLUDE|ACK_TLVS)", buf, buflen);
|
|
flag_write(flags, 0x0400, "(ATOMIC|CREATE)", buf, buflen);
|
|
flag_write(flags, 0x0800, "(DUMP|APPEND)", buf, buflen);
|
|
|
|
return (bufp);
|
|
}
|
|
|
|
const char *if_flags2str(uint32_t flags, char *buf, size_t buflen)
|
|
{
|
|
const char *bufp = buf;
|
|
|
|
*buf = 0;
|
|
flag_write(flags, IFF_UP, "UP", buf, buflen);
|
|
flag_write(flags, IFF_BROADCAST, "BROADCAST", buf, buflen);
|
|
flag_write(flags, IFF_DEBUG, "DEBUG", buf, buflen);
|
|
flag_write(flags, IFF_LOOPBACK, "LOOPBACK", buf, buflen);
|
|
flag_write(flags, IFF_POINTOPOINT, "POINTOPOINT", buf, buflen);
|
|
flag_write(flags, IFF_NOTRAILERS, "NOTRAILERS", buf, buflen);
|
|
flag_write(flags, IFF_RUNNING, "RUNNING", buf, buflen);
|
|
flag_write(flags, IFF_NOARP, "NOARP", buf, buflen);
|
|
flag_write(flags, IFF_PROMISC, "PROMISC", buf, buflen);
|
|
flag_write(flags, IFF_ALLMULTI, "ALLMULTI", buf, buflen);
|
|
flag_write(flags, IFF_MASTER, "MASTER", buf, buflen);
|
|
flag_write(flags, IFF_SLAVE, "SLAVE", buf, buflen);
|
|
flag_write(flags, IFF_MULTICAST, "MULTICAST", buf, buflen);
|
|
flag_write(flags, IFF_PORTSEL, "PORTSEL", buf, buflen);
|
|
flag_write(flags, IFF_AUTOMEDIA, "AUTOMEDIA", buf, buflen);
|
|
flag_write(flags, IFF_DYNAMIC, "DYNAMIC", buf, buflen);
|
|
|
|
return (bufp);
|
|
}
|
|
|
|
const char *rtm_flags2str(uint32_t flags, char *buf, size_t buflen)
|
|
{
|
|
const char *bufp = buf;
|
|
|
|
*buf = 0;
|
|
flag_write(flags, RTM_F_NOTIFY, "NOTIFY", buf, buflen);
|
|
flag_write(flags, RTM_F_CLONED, "CLONED", buf, buflen);
|
|
flag_write(flags, RTM_F_EQUALIZE, "EQUALIZE", buf, buflen);
|
|
|
|
return (bufp);
|
|
}
|
|
|
|
const char *neigh_state2str(uint32_t flags, char *buf, size_t buflen)
|
|
{
|
|
const char *bufp = buf;
|
|
|
|
*buf = 0;
|
|
flag_write(flags, NUD_INCOMPLETE, "INCOMPLETE", buf, buflen);
|
|
flag_write(flags, NUD_REACHABLE, "REACHABLE", buf, buflen);
|
|
flag_write(flags, NUD_STALE, "STALE", buf, buflen);
|
|
flag_write(flags, NUD_DELAY, "DELAY", buf, buflen);
|
|
flag_write(flags, NUD_PROBE, "PROBE", buf, buflen);
|
|
flag_write(flags, NUD_FAILED, "FAILED", buf, buflen);
|
|
flag_write(flags, NUD_NOARP, "NOARP", buf, buflen);
|
|
flag_write(flags, NUD_PERMANENT, "PERMANENT", buf, buflen);
|
|
|
|
return (bufp);
|
|
}
|
|
|
|
const char *neigh_flags2str(uint32_t flags, char *buf, size_t buflen)
|
|
{
|
|
const char *bufp = buf;
|
|
|
|
*buf = 0;
|
|
flag_write(flags, NTF_USE, "USE", buf, buflen);
|
|
flag_write(flags, NTF_SELF, "SELF", buf, buflen);
|
|
flag_write(flags, NTF_MASTER, "MASTER", buf, buflen);
|
|
flag_write(flags, NTF_PROXY, "PROXY", buf, buflen);
|
|
flag_write(flags, NTF_EXT_LEARNED, "EXT_LEARNED", buf, buflen);
|
|
#ifdef NTF_OFFLOADED
|
|
flag_write(flags, NTF_OFFLOADED, "OFFLOADED", buf, buflen);
|
|
#endif /* NTF_OFFLOADED */
|
|
flag_write(flags, NTF_ROUTER, "ROUTER", buf, buflen);
|
|
|
|
return (bufp);
|
|
}
|
|
|
|
const char *ifa_flags2str(uint32_t flags, char *buf, size_t buflen)
|
|
{
|
|
const char *bufp = buf;
|
|
|
|
*buf = 0;
|
|
flag_write(flags, IFA_F_SECONDARY, "SECONDARY", buf, buflen);
|
|
flag_write(flags, IFA_F_NODAD, "NODAD", buf, buflen);
|
|
flag_write(flags, IFA_F_OPTIMISTIC, "OPTIMISTIC", buf, buflen);
|
|
flag_write(flags, IFA_F_DADFAILED, "DADFAILED", buf, buflen);
|
|
flag_write(flags, IFA_F_HOMEADDRESS, "HOMEADDRESS", buf, buflen);
|
|
flag_write(flags, IFA_F_DEPRECATED, "DEPRECATED", buf, buflen);
|
|
flag_write(flags, IFA_F_TENTATIVE, "TENTATIVE", buf, buflen);
|
|
flag_write(flags, IFA_F_PERMANENT, "PERMANENT", buf, buflen);
|
|
flag_write(flags, IFA_F_MANAGETEMPADDR, "MANAGETEMPADDR", buf, buflen);
|
|
flag_write(flags, IFA_F_NOPREFIXROUTE, "NOPREFIXROUTE", buf, buflen);
|
|
flag_write(flags, IFA_F_MCAUTOJOIN, "MCAUTOJOIN", buf, buflen);
|
|
flag_write(flags, IFA_F_STABLE_PRIVACY, "STABLE_PRIVACY", buf, buflen);
|
|
|
|
return (bufp);
|
|
}
|
|
|
|
const char *nh_flags2str(uint32_t flags, char *buf, size_t buflen)
|
|
{
|
|
const char *bufp = buf;
|
|
|
|
*buf = 0;
|
|
flag_write(flags, RTNH_F_DEAD, "DEAD", buf, buflen);
|
|
flag_write(flags, RTNH_F_PERVASIVE, "PERVASIVE", buf, buflen);
|
|
flag_write(flags, RTNH_F_ONLINK, "ONLINK", buf, buflen);
|
|
flag_write(flags, RTNH_F_OFFLOAD, "OFFLOAD", buf, buflen);
|
|
flag_write(flags, RTNH_F_LINKDOWN, "LINKDOWN", buf, buflen);
|
|
flag_write(flags, RTNH_F_UNRESOLVED, "UNRESOLVED", buf, buflen);
|
|
|
|
return (bufp);
|
|
}
|
|
|
|
/*
|
|
* Netlink abstractions.
|
|
*/
|
|
static void nllink_pdr_dump(struct rtattr *rta, size_t msglen)
|
|
{
|
|
size_t plen;
|
|
uint32_t u32v;
|
|
|
|
next_rta:
|
|
/* Check the header for valid length and for outbound access. */
|
|
if (RTA_OK(rta, msglen) == 0)
|
|
return;
|
|
|
|
plen = RTA_PAYLOAD(rta);
|
|
zlog_debug(" linkinfo [len=%d (payload=%zu) type=(%d) %s]",
|
|
rta->rta_len, plen, rta->rta_type,
|
|
ifla_pdr_type2str(rta->rta_type));
|
|
switch (rta->rta_type) {
|
|
case IFLA_PROTO_DOWN_REASON_MASK:
|
|
case IFLA_PROTO_DOWN_REASON_VALUE:
|
|
if (plen < sizeof(uint32_t)) {
|
|
zlog_debug(" invalid length");
|
|
break;
|
|
}
|
|
|
|
u32v = *(uint32_t *)RTA_DATA(rta);
|
|
zlog_debug(" %u", u32v);
|
|
break;
|
|
|
|
default:
|
|
/* NOTHING: unhandled. */
|
|
break;
|
|
}
|
|
|
|
/* Get next pointer and start iteration again. */
|
|
rta = RTA_NEXT(rta, msglen);
|
|
goto next_rta;
|
|
}
|
|
|
|
static void nllink_linkinfo_dump(struct rtattr *rta, size_t msglen)
|
|
{
|
|
size_t plen;
|
|
char dbuf[128];
|
|
|
|
next_rta:
|
|
/* Check the header for valid length and for outbound access. */
|
|
if (RTA_OK(rta, msglen) == 0)
|
|
return;
|
|
|
|
plen = RTA_PAYLOAD(rta);
|
|
zlog_debug(" linkinfo [len=%d (payload=%zu) type=(%d) %s]",
|
|
rta->rta_len, plen, rta->rta_type,
|
|
ifla_info_type2str(rta->rta_type));
|
|
switch (rta->rta_type) {
|
|
case IFLA_INFO_KIND:
|
|
if (plen == 0) {
|
|
zlog_debug(" invalid length");
|
|
break;
|
|
}
|
|
|
|
snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta));
|
|
zlog_debug(" %s", dbuf);
|
|
break;
|
|
case IFLA_INFO_SLAVE_KIND:
|
|
if (plen == 0) {
|
|
zlog_debug(" invalid length");
|
|
break;
|
|
}
|
|
|
|
snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta));
|
|
zlog_debug(" %s", dbuf);
|
|
break;
|
|
|
|
default:
|
|
/* NOTHING: unhandled. */
|
|
break;
|
|
}
|
|
|
|
/* Get next pointer and start iteration again. */
|
|
rta = RTA_NEXT(rta, msglen);
|
|
goto next_rta;
|
|
}
|
|
|
|
static void nllink_dump(struct ifinfomsg *ifi, size_t msglen)
|
|
{
|
|
uint8_t *datap;
|
|
struct rtattr *rta;
|
|
size_t plen, it;
|
|
uint32_t u32v;
|
|
uint8_t u8v;
|
|
char bytestr[16];
|
|
char dbuf[128];
|
|
unsigned short rta_type;
|
|
|
|
/* Get the first attribute and go from there. */
|
|
rta = IFLA_RTA(ifi);
|
|
next_rta:
|
|
/* Check the header for valid length and for outbound access. */
|
|
if (RTA_OK(rta, msglen) == 0)
|
|
return;
|
|
|
|
plen = RTA_PAYLOAD(rta);
|
|
rta_type = rta->rta_type & ~NLA_F_NESTED;
|
|
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
|
|
plen, rta_type, rta_type2str(rta_type));
|
|
switch (rta_type) {
|
|
case IFLA_IFNAME:
|
|
case IFLA_IFALIAS:
|
|
if (plen == 0) {
|
|
zlog_debug(" invalid length");
|
|
break;
|
|
}
|
|
|
|
snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta));
|
|
zlog_debug(" %s", dbuf);
|
|
break;
|
|
|
|
case IFLA_MTU:
|
|
case IFLA_TXQLEN:
|
|
case IFLA_NUM_TX_QUEUES:
|
|
case IFLA_NUM_RX_QUEUES:
|
|
case IFLA_GROUP:
|
|
case IFLA_PROMISCUITY:
|
|
#ifdef IFLA_GSO_MAX_SEGS
|
|
case IFLA_GSO_MAX_SEGS:
|
|
#endif /* IFLA_GSO_MAX_SEGS */
|
|
#ifdef IFLA_GSO_MAX_SIZE
|
|
case IFLA_GSO_MAX_SIZE:
|
|
#endif /* IFLA_GSO_MAX_SIZE */
|
|
case IFLA_CARRIER_CHANGES:
|
|
case IFLA_MASTER:
|
|
case IFLA_LINK:
|
|
if (plen < sizeof(uint32_t)) {
|
|
zlog_debug(" invalid length");
|
|
break;
|
|
}
|
|
|
|
u32v = *(uint32_t *)RTA_DATA(rta);
|
|
zlog_debug(" %u", u32v);
|
|
break;
|
|
|
|
case IFLA_PROTO_DOWN:
|
|
if (plen < sizeof(uint8_t)) {
|
|
zlog_debug(" invalid length");
|
|
break;
|
|
}
|
|
|
|
u8v = *(uint8_t *)RTA_DATA(rta);
|
|
zlog_debug(" %u", u8v);
|
|
break;
|
|
case IFLA_ADDRESS:
|
|
datap = RTA_DATA(rta);
|
|
dbuf[0] = 0;
|
|
for (it = 0; it < plen; it++) {
|
|
snprintf(bytestr, sizeof(bytestr), "%02X:", *datap);
|
|
strlcat(dbuf, bytestr, sizeof(dbuf));
|
|
datap++;
|
|
}
|
|
/* Remove trailing ':'. */
|
|
if (dbuf[0])
|
|
dbuf[strlen(dbuf) - 1] = 0;
|
|
|
|
zlog_debug(" %s", dbuf[0] ? dbuf : "<empty>");
|
|
break;
|
|
|
|
case IFLA_LINKINFO:
|
|
nllink_linkinfo_dump(RTA_DATA(rta), plen);
|
|
break;
|
|
|
|
case IFLA_PROTO_DOWN_REASON:
|
|
nllink_pdr_dump(RTA_DATA(rta), plen);
|
|
break;
|
|
|
|
default:
|
|
/* NOTHING: unhandled. */
|
|
break;
|
|
}
|
|
|
|
/* Get next pointer and start iteration again. */
|
|
rta = RTA_NEXT(rta, msglen);
|
|
goto next_rta;
|
|
}
|
|
|
|
static void nlroute_dump(struct rtmsg *rtm, size_t msglen)
|
|
{
|
|
struct rta_mfc_stats *mfc_stats;
|
|
struct rtattr *rta;
|
|
size_t plen;
|
|
uint32_t u32v;
|
|
uint64_t u64v;
|
|
|
|
/* Get the first attribute and go from there. */
|
|
rta = RTM_RTA(rtm);
|
|
next_rta:
|
|
/* Check the header for valid length and for outbound access. */
|
|
if (RTA_OK(rta, msglen) == 0)
|
|
return;
|
|
|
|
plen = RTA_PAYLOAD(rta);
|
|
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
|
|
plen, rta->rta_type & NLA_TYPE_MASK,
|
|
rtm_rta2str(rta->rta_type & NLA_TYPE_MASK));
|
|
switch (rta->rta_type & NLA_TYPE_MASK) {
|
|
case RTA_IIF:
|
|
case RTA_OIF:
|
|
case RTA_PRIORITY:
|
|
case RTA_TABLE:
|
|
case RTA_NH_ID:
|
|
u32v = *(uint32_t *)RTA_DATA(rta);
|
|
zlog_debug(" %u", u32v);
|
|
break;
|
|
|
|
case RTA_EXPIRES:
|
|
u64v = *(uint64_t *)RTA_DATA(rta);
|
|
zlog_debug(" %" PRIu64, u64v);
|
|
break;
|
|
|
|
case RTA_GATEWAY:
|
|
case RTA_DST:
|
|
case RTA_SRC:
|
|
case RTA_PREFSRC:
|
|
switch (plen) {
|
|
case sizeof(struct in_addr):
|
|
zlog_debug(" %pI4",
|
|
(struct in_addr *)RTA_DATA(rta));
|
|
break;
|
|
case sizeof(struct in6_addr):
|
|
zlog_debug(" %pI6",
|
|
(struct in6_addr *)RTA_DATA(rta));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case RTA_MFC_STATS:
|
|
mfc_stats = (struct rta_mfc_stats *)RTA_DATA(rta);
|
|
zlog_debug(" pkts=%ju bytes=%ju wrong_if=%ju",
|
|
(uintmax_t)mfc_stats->mfcs_packets,
|
|
(uintmax_t)mfc_stats->mfcs_bytes,
|
|
(uintmax_t)mfc_stats->mfcs_wrong_if);
|
|
break;
|
|
|
|
default:
|
|
/* NOTHING: unhandled. */
|
|
break;
|
|
}
|
|
|
|
/* Get next pointer and start iteration again. */
|
|
rta = RTA_NEXT(rta, msglen);
|
|
goto next_rta;
|
|
}
|
|
|
|
static void nlneigh_dump(struct ndmsg *ndm, size_t msglen)
|
|
{
|
|
struct rtattr *rta;
|
|
uint8_t *datap;
|
|
size_t plen, it;
|
|
uint16_t vid;
|
|
char bytestr[16];
|
|
char dbuf[128];
|
|
unsigned short rta_type;
|
|
|
|
#ifndef NDA_RTA
|
|
#define NDA_RTA(ndm) \
|
|
/* struct ndmsg *ndm; */ \
|
|
((struct rtattr *)(((uint8_t *)(ndm)) \
|
|
+ NLMSG_ALIGN(sizeof(struct ndmsg))))
|
|
#endif /* NDA_RTA */
|
|
|
|
/* Get the first attribute and go from there. */
|
|
rta = NDA_RTA(ndm);
|
|
next_rta:
|
|
/* Check the header for valid length and for outbound access. */
|
|
if (RTA_OK(rta, msglen) == 0)
|
|
return;
|
|
|
|
plen = RTA_PAYLOAD(rta);
|
|
rta_type = rta->rta_type & ~NLA_F_NESTED;
|
|
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
|
|
plen, rta->rta_type, neigh_rta2str(rta_type));
|
|
switch (rta_type) {
|
|
case NDA_LLADDR:
|
|
datap = RTA_DATA(rta);
|
|
dbuf[0] = 0;
|
|
for (it = 0; it < plen; it++) {
|
|
snprintf(bytestr, sizeof(bytestr), "%02X:", *datap);
|
|
strlcat(dbuf, bytestr, sizeof(dbuf));
|
|
datap++;
|
|
}
|
|
/* Remove trailing ':'. */
|
|
if (dbuf[0])
|
|
dbuf[strlen(dbuf) - 1] = 0;
|
|
|
|
zlog_debug(" %s", dbuf[0] ? dbuf : "<empty>");
|
|
break;
|
|
|
|
case NDA_DST:
|
|
switch (plen) {
|
|
case sizeof(struct in_addr):
|
|
zlog_debug(" %pI4",
|
|
(struct in_addr *)RTA_DATA(rta));
|
|
break;
|
|
case sizeof(struct in6_addr):
|
|
zlog_debug(" %pI6",
|
|
(struct in6_addr *)RTA_DATA(rta));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NDA_VLAN:
|
|
vid = *(uint16_t *)RTA_DATA(rta);
|
|
zlog_debug(" %d", vid);
|
|
break;
|
|
|
|
default:
|
|
/* NOTHING: unhandled. */
|
|
break;
|
|
}
|
|
|
|
/* Get next pointer and start iteration again. */
|
|
rta = RTA_NEXT(rta, msglen);
|
|
goto next_rta;
|
|
}
|
|
|
|
static void nlifa_dump(struct ifaddrmsg *ifa, size_t msglen)
|
|
{
|
|
struct rtattr *rta;
|
|
size_t plen;
|
|
uint32_t u32v;
|
|
|
|
/* Get the first attribute and go from there. */
|
|
rta = IFA_RTA(ifa);
|
|
next_rta:
|
|
/* Check the header for valid length and for outbound access. */
|
|
if (RTA_OK(rta, msglen) == 0)
|
|
return;
|
|
|
|
plen = RTA_PAYLOAD(rta);
|
|
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
|
|
plen, rta->rta_type, ifa_rta2str(rta->rta_type));
|
|
switch (rta->rta_type) {
|
|
case IFA_UNSPEC:
|
|
u32v = *(uint32_t *)RTA_DATA(rta);
|
|
zlog_debug(" %u", u32v);
|
|
break;
|
|
|
|
case IFA_LABEL:
|
|
zlog_debug(" %s", (const char *)RTA_DATA(rta));
|
|
break;
|
|
|
|
case IFA_ADDRESS:
|
|
case IFA_LOCAL:
|
|
case IFA_BROADCAST:
|
|
switch (plen) {
|
|
case 4:
|
|
zlog_debug(" %pI4",
|
|
(struct in_addr *)RTA_DATA(rta));
|
|
break;
|
|
case 16:
|
|
zlog_debug(" %pI6",
|
|
(struct in6_addr *)RTA_DATA(rta));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
/* NOTHING: unhandled. */
|
|
break;
|
|
}
|
|
|
|
/* Get next pointer and start iteration again. */
|
|
rta = RTA_NEXT(rta, msglen);
|
|
goto next_rta;
|
|
}
|
|
|
|
static void nltnl_dump(struct tunnel_msg *tnlm, size_t msglen)
|
|
{
|
|
struct rtattr *attr;
|
|
vni_t vni_start = 0, vni_end = 0;
|
|
struct rtattr *ttb[VXLAN_VNIFILTER_ENTRY_MAX + 1];
|
|
uint8_t rta_type;
|
|
|
|
attr = TUNNEL_RTA(tnlm);
|
|
next_attr:
|
|
/* Check the header for valid length and for outbound access. */
|
|
if (RTA_OK(attr, msglen) == 0)
|
|
return;
|
|
|
|
rta_type = attr->rta_type & NLA_TYPE_MASK;
|
|
|
|
if (rta_type != VXLAN_VNIFILTER_ENTRY) {
|
|
attr = RTA_NEXT(attr, msglen);
|
|
goto next_attr;
|
|
}
|
|
|
|
memset(ttb, 0, sizeof(ttb));
|
|
|
|
netlink_parse_rtattr_flags(ttb, VXLAN_VNIFILTER_ENTRY_MAX,
|
|
RTA_DATA(attr), RTA_PAYLOAD(attr),
|
|
NLA_F_NESTED);
|
|
|
|
if (ttb[VXLAN_VNIFILTER_ENTRY_START])
|
|
vni_start =
|
|
*(uint32_t *)RTA_DATA(ttb[VXLAN_VNIFILTER_ENTRY_START]);
|
|
|
|
if (ttb[VXLAN_VNIFILTER_ENTRY_END])
|
|
vni_end = *(uint32_t *)RTA_DATA(ttb[VXLAN_VNIFILTER_ENTRY_END]);
|
|
zlog_debug(" vni_start %u, vni_end %u", vni_start, vni_end);
|
|
|
|
attr = RTA_NEXT(attr, msglen);
|
|
goto next_attr;
|
|
}
|
|
|
|
static const char *lwt_type2str(uint16_t type)
|
|
{
|
|
switch (type) {
|
|
case LWTUNNEL_ENCAP_NONE:
|
|
return "NONE";
|
|
case LWTUNNEL_ENCAP_MPLS:
|
|
return "MPLS";
|
|
case LWTUNNEL_ENCAP_IP:
|
|
return "IPv4";
|
|
case LWTUNNEL_ENCAP_ILA:
|
|
return "ILA";
|
|
case LWTUNNEL_ENCAP_IP6:
|
|
return "IPv6";
|
|
case LWTUNNEL_ENCAP_SEG6:
|
|
return "SEG6";
|
|
case LWTUNNEL_ENCAP_BPF:
|
|
return "BPF";
|
|
case LWTUNNEL_ENCAP_SEG6_LOCAL:
|
|
return "SEG6_LOCAL";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
static const char *nhg_type2str(uint16_t type)
|
|
{
|
|
switch (type) {
|
|
case NEXTHOP_GRP_TYPE_MPATH:
|
|
return "MULTIPATH";
|
|
case NEXTHOP_GRP_TYPE_RES:
|
|
return "RESILIENT MULTIPATH";
|
|
default:
|
|
return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
static void nlnh_dump(struct nhmsg *nhm, size_t msglen)
|
|
{
|
|
struct rtattr *rta;
|
|
int ifindex;
|
|
size_t plen;
|
|
uint16_t u16v;
|
|
uint32_t u32v;
|
|
unsigned long count, i;
|
|
struct nexthop_grp *nhgrp;
|
|
unsigned short rta_type;
|
|
|
|
rta = RTM_NHA(nhm);
|
|
|
|
next_rta:
|
|
/* Check the header for valid length and for outbound access. */
|
|
if (RTA_OK(rta, msglen) == 0)
|
|
return;
|
|
|
|
plen = RTA_PAYLOAD(rta);
|
|
rta_type = rta->rta_type & ~NLA_F_NESTED;
|
|
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
|
|
plen, rta->rta_type, nhm_rta2str(rta_type));
|
|
switch (rta_type) {
|
|
case NHA_ID:
|
|
u32v = *(uint32_t *)RTA_DATA(rta);
|
|
zlog_debug(" %u", u32v);
|
|
break;
|
|
case NHA_GROUP:
|
|
nhgrp = (struct nexthop_grp *)RTA_DATA(rta);
|
|
count = (RTA_PAYLOAD(rta) / sizeof(*nhgrp));
|
|
if (count == 0
|
|
|| (count * sizeof(*nhgrp)) != RTA_PAYLOAD(rta)) {
|
|
zlog_debug(" invalid nexthop group received");
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < count; i++)
|
|
zlog_debug(" id %d weight %d", nhgrp[i].id,
|
|
nhgrp[i].weight);
|
|
break;
|
|
case NHA_ENCAP_TYPE:
|
|
u16v = *(uint16_t *)RTA_DATA(rta);
|
|
zlog_debug(" %s", lwt_type2str(u16v));
|
|
break;
|
|
case NHA_GROUP_TYPE:
|
|
u16v = *(uint16_t *)RTA_DATA(rta);
|
|
zlog_debug(" %s", nhg_type2str(u16v));
|
|
break;
|
|
case NHA_BLACKHOLE:
|
|
/* NOTHING */
|
|
break;
|
|
case NHA_OIF:
|
|
ifindex = *(int *)RTA_DATA(rta);
|
|
zlog_debug(" %d", ifindex);
|
|
break;
|
|
case NHA_GATEWAY:
|
|
switch (nhm->nh_family) {
|
|
case AF_INET:
|
|
zlog_debug(" %pI4",
|
|
(struct in_addr *)RTA_DATA(rta));
|
|
break;
|
|
case AF_INET6:
|
|
zlog_debug(" %pI6",
|
|
(struct in6_addr *)RTA_DATA(rta));
|
|
break;
|
|
|
|
default:
|
|
zlog_debug(" invalid family %d", nhm->nh_family);
|
|
break;
|
|
}
|
|
break;
|
|
case NHA_ENCAP:
|
|
/* TODO: handle MPLS labels. */
|
|
zlog_debug(" unparsed MPLS labels");
|
|
break;
|
|
case NHA_GROUPS:
|
|
/* TODO: handle this message. */
|
|
zlog_debug(" unparsed GROUPS message");
|
|
break;
|
|
|
|
default:
|
|
/* NOTHING: unhandled. */
|
|
break;
|
|
}
|
|
|
|
/* Get next pointer and start iteration again. */
|
|
rta = RTA_NEXT(rta, msglen);
|
|
goto next_rta;
|
|
}
|
|
|
|
static void nlrule_dump(struct fib_rule_hdr *frh, size_t msglen)
|
|
{
|
|
struct rtattr *rta;
|
|
size_t plen;
|
|
uint8_t u8v;
|
|
uint32_t u32v;
|
|
int32_t s32v;
|
|
uint64_t u64v;
|
|
char dbuf[128];
|
|
struct fib_rule_uid_range *u_range;
|
|
struct fib_rule_port_range *p_range;
|
|
|
|
/* Get the first attribute and go from there. */
|
|
rta = RTM_RTA(frh);
|
|
next_rta:
|
|
/* Check the header for valid length and for outbound access. */
|
|
if (RTA_OK(rta, msglen) == 0)
|
|
return;
|
|
|
|
plen = RTA_PAYLOAD(rta);
|
|
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
|
|
plen, rta->rta_type, frh_rta2str(rta->rta_type));
|
|
switch (rta->rta_type) {
|
|
case FRA_DST:
|
|
case FRA_SRC:
|
|
switch (plen) {
|
|
case sizeof(struct in_addr):
|
|
zlog_debug(" %pI4",
|
|
(struct in_addr *)RTA_DATA(rta));
|
|
break;
|
|
case sizeof(struct in6_addr):
|
|
zlog_debug(" %pI6",
|
|
(struct in6_addr *)RTA_DATA(rta));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case FRA_IIFNAME:
|
|
case FRA_OIFNAME:
|
|
snprintf(dbuf, sizeof(dbuf), "%s", (char *)RTA_DATA(rta));
|
|
zlog_debug(" %s", dbuf);
|
|
break;
|
|
|
|
case FRA_GOTO:
|
|
case FRA_UNUSED2:
|
|
case FRA_PRIORITY:
|
|
case FRA_UNUSED3:
|
|
case FRA_UNUSED4:
|
|
case FRA_UNUSED5:
|
|
case FRA_FWMARK:
|
|
case FRA_FLOW:
|
|
case FRA_TABLE:
|
|
case FRA_FWMASK:
|
|
u32v = *(uint32_t *)RTA_DATA(rta);
|
|
zlog_debug(" %u", u32v);
|
|
break;
|
|
|
|
case FRA_SUPPRESS_IFGROUP:
|
|
case FRA_SUPPRESS_PREFIXLEN:
|
|
s32v = *(int32_t *)RTA_DATA(rta);
|
|
zlog_debug(" %d", s32v);
|
|
break;
|
|
|
|
case FRA_TUN_ID:
|
|
u64v = *(uint64_t *)RTA_DATA(rta);
|
|
zlog_debug(" %" PRIu64, u64v);
|
|
break;
|
|
|
|
case FRA_L3MDEV:
|
|
case FRA_PROTOCOL:
|
|
case FRA_IP_PROTO:
|
|
u8v = *(uint8_t *)RTA_DATA(rta);
|
|
zlog_debug(" %u", u8v);
|
|
break;
|
|
|
|
case FRA_UID_RANGE:
|
|
u_range = (struct fib_rule_uid_range *)RTA_DATA(rta);
|
|
if (u_range->start == u_range->end)
|
|
zlog_debug(" %u", u_range->start);
|
|
else
|
|
zlog_debug(" %u-%u", u_range->start, u_range->end);
|
|
break;
|
|
|
|
case FRA_SPORT_RANGE:
|
|
case FRA_DPORT_RANGE:
|
|
p_range = (struct fib_rule_port_range *)RTA_DATA(rta);
|
|
if (p_range->start == p_range->end)
|
|
zlog_debug(" %u", p_range->start);
|
|
else
|
|
zlog_debug(" %u-%u", p_range->start, p_range->end);
|
|
break;
|
|
|
|
case FRA_PAD: /* fallthrough */
|
|
default:
|
|
/* NOTHING: unhandled. */
|
|
break;
|
|
}
|
|
|
|
/* Get next pointer and start iteration again. */
|
|
rta = RTA_NEXT(rta, msglen);
|
|
goto next_rta;
|
|
}
|
|
|
|
static const char *tcm_nltype2str(int nltype)
|
|
{
|
|
switch (nltype) {
|
|
case RTM_NEWQDISC:
|
|
case RTM_DELQDISC:
|
|
return "qdisc";
|
|
case RTM_NEWTCLASS:
|
|
case RTM_DELTCLASS:
|
|
return "tclass";
|
|
case RTM_NEWTFILTER:
|
|
case RTM_DELTFILTER:
|
|
return "tfilter";
|
|
default:
|
|
/* should never hit */
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
static void nlncm_dump(const struct netconfmsg *ncm, size_t msglen)
|
|
{
|
|
const struct rtattr *rta;
|
|
size_t plen;
|
|
uint32_t ival;
|
|
|
|
rta = (void *)((const char *)ncm +
|
|
NLMSG_ALIGN(sizeof(struct netconfmsg)));
|
|
|
|
next_rta:
|
|
/* Check the attr header for valid length. */
|
|
if (RTA_OK(rta, msglen) == 0)
|
|
return;
|
|
|
|
plen = RTA_PAYLOAD(rta);
|
|
|
|
zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len,
|
|
plen, rta->rta_type, ncm_rta2str(rta->rta_type));
|
|
|
|
switch (rta->rta_type) {
|
|
case NETCONFA_IFINDEX:
|
|
ival = *(uint32_t *)RTA_DATA(rta);
|
|
zlog_debug(" %d", (int32_t)ival);
|
|
break;
|
|
|
|
/* Most attrs are just on/off. */
|
|
case NETCONFA_FORWARDING:
|
|
case NETCONFA_RP_FILTER:
|
|
case NETCONFA_MC_FORWARDING:
|
|
case NETCONFA_PROXY_NEIGH:
|
|
case NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN:
|
|
case NETCONFA_INPUT:
|
|
case NETCONFA_BC_FORWARDING:
|
|
ival = *(uint32_t *)RTA_DATA(rta);
|
|
dump_on_off(ival, " ");
|
|
break;
|
|
default:
|
|
/* NOTHING: unhandled. */
|
|
break;
|
|
}
|
|
|
|
/* Get next pointer and start iteration again. */
|
|
rta = RTA_NEXT(rta, msglen);
|
|
goto next_rta;
|
|
}
|
|
|
|
void nl_dump(void *msg, size_t msglen)
|
|
{
|
|
struct nlmsghdr *nlmsg = msg;
|
|
struct nlmsgerr *nlmsgerr;
|
|
struct rtgenmsg *rtgen;
|
|
struct ifaddrmsg *ifa;
|
|
struct ndmsg *ndm;
|
|
struct rtmsg *rtm;
|
|
struct nhmsg *nhm;
|
|
struct netconfmsg *ncm;
|
|
struct ifinfomsg *ifi;
|
|
struct tunnel_msg *tnlm;
|
|
struct fib_rule_hdr *frh;
|
|
struct tcmsg *tcm;
|
|
|
|
char fbuf[128];
|
|
char ibuf[128];
|
|
|
|
next_header:
|
|
zlog_debug(
|
|
"nlmsghdr [len=%u type=(%d) %s flags=(0x%04x) {%s} seq=%u pid=%u]",
|
|
nlmsg->nlmsg_len, nlmsg->nlmsg_type,
|
|
nlmsg_type2str(nlmsg->nlmsg_type), nlmsg->nlmsg_flags,
|
|
nlmsg_flags2str(nlmsg->nlmsg_flags, fbuf, sizeof(fbuf)),
|
|
nlmsg->nlmsg_seq, nlmsg->nlmsg_pid);
|
|
|
|
switch (nlmsg->nlmsg_type) {
|
|
/* Generic. */
|
|
case NLMSG_NOOP:
|
|
break;
|
|
case NLMSG_ERROR:
|
|
nlmsgerr = NLMSG_DATA(nlmsg);
|
|
zlog_debug(" nlmsgerr [error=(%d) %s]", nlmsgerr->error,
|
|
strerror(-nlmsgerr->error));
|
|
break;
|
|
case NLMSG_DONE:
|
|
return;
|
|
case NLMSG_OVERRUN:
|
|
break;
|
|
|
|
/* RTM. */
|
|
case RTM_NEWLINK:
|
|
case RTM_DELLINK:
|
|
case RTM_SETLINK:
|
|
ifi = NLMSG_DATA(nlmsg);
|
|
zlog_debug(
|
|
" ifinfomsg [family=%d type=(%d) %s index=%d flags=0x%04x {%s}]",
|
|
ifi->ifi_family, ifi->ifi_type,
|
|
ifi_type2str(ifi->ifi_type), ifi->ifi_index,
|
|
ifi->ifi_flags,
|
|
if_flags2str(ifi->ifi_flags, ibuf, sizeof(ibuf)));
|
|
nllink_dump(ifi, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)));
|
|
break;
|
|
case RTM_GETLINK:
|
|
rtgen = NLMSG_DATA(nlmsg);
|
|
zlog_debug(" rtgen [family=(%d) %s]", rtgen->rtgen_family,
|
|
af_type2str(rtgen->rtgen_family));
|
|
break;
|
|
|
|
case RTM_NEWROUTE:
|
|
case RTM_DELROUTE:
|
|
case RTM_GETROUTE:
|
|
rtm = NLMSG_DATA(nlmsg);
|
|
zlog_debug(
|
|
" rtmsg [family=(%d) %s dstlen=%d srclen=%d tos=%d table=%d protocol=(%d) %s scope=(%d) %s type=(%d) %s flags=0x%04x {%s}]",
|
|
rtm->rtm_family, af_type2str(rtm->rtm_family),
|
|
rtm->rtm_dst_len, rtm->rtm_src_len, rtm->rtm_tos,
|
|
rtm->rtm_table, rtm->rtm_protocol,
|
|
rtm_protocol2str(rtm->rtm_protocol), rtm->rtm_scope,
|
|
rtm_scope2str(rtm->rtm_scope), rtm->rtm_type,
|
|
rtm_type2str(rtm->rtm_type), rtm->rtm_flags,
|
|
rtm_flags2str(rtm->rtm_flags, fbuf, sizeof(fbuf)));
|
|
nlroute_dump(rtm,
|
|
nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*rtm)));
|
|
break;
|
|
|
|
case RTM_NEWNEIGH:
|
|
case RTM_DELNEIGH:
|
|
ndm = NLMSG_DATA(nlmsg);
|
|
zlog_debug(
|
|
" ndm [family=%d (%s) ifindex=%d state=0x%04x {%s} flags=0x%04x {%s} type=%d (%s)]",
|
|
ndm->ndm_family, af_type2str(ndm->ndm_family),
|
|
ndm->ndm_ifindex, ndm->ndm_state,
|
|
neigh_state2str(ndm->ndm_state, ibuf, sizeof(ibuf)),
|
|
ndm->ndm_flags,
|
|
neigh_flags2str(ndm->ndm_flags, fbuf, sizeof(fbuf)),
|
|
ndm->ndm_type, rtm_type2str(ndm->ndm_type));
|
|
nlneigh_dump(ndm,
|
|
nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ndm)));
|
|
break;
|
|
|
|
case RTM_NEWRULE:
|
|
case RTM_DELRULE:
|
|
frh = NLMSG_DATA(nlmsg);
|
|
zlog_debug(
|
|
" frh [family=%d (%s) dst_len=%d src_len=%d tos=%d table=%d res1=%d res2=%d action=%d (%s) flags=0x%x]",
|
|
frh->family, af_type2str(frh->family), frh->dst_len,
|
|
frh->src_len, frh->tos, frh->table, frh->res1,
|
|
frh->res2, frh->action, frh_action2str(frh->action),
|
|
frh->flags);
|
|
nlrule_dump(frh, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*frh)));
|
|
break;
|
|
|
|
|
|
case RTM_NEWADDR:
|
|
case RTM_DELADDR:
|
|
ifa = NLMSG_DATA(nlmsg);
|
|
zlog_debug(
|
|
" ifa [family=(%d) %s prefixlen=%d flags=0x%04x {%s} scope=%d index=%u]",
|
|
ifa->ifa_family, af_type2str(ifa->ifa_family),
|
|
ifa->ifa_prefixlen, ifa->ifa_flags,
|
|
if_flags2str(ifa->ifa_flags, fbuf, sizeof(fbuf)),
|
|
ifa->ifa_scope, ifa->ifa_index);
|
|
nlifa_dump(ifa, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
|
|
break;
|
|
|
|
case RTM_NEWNEXTHOP:
|
|
case RTM_DELNEXTHOP:
|
|
case RTM_GETNEXTHOP:
|
|
nhm = NLMSG_DATA(nlmsg);
|
|
zlog_debug(
|
|
" nhm [family=(%d) %s scope=(%d) %s protocol=(%d) %s flags=0x%08x {%s}]",
|
|
nhm->nh_family, af_type2str(nhm->nh_family),
|
|
nhm->nh_scope, rtm_scope2str(nhm->nh_scope),
|
|
nhm->nh_protocol, rtm_protocol2str(nhm->nh_protocol),
|
|
nhm->nh_flags,
|
|
nh_flags2str(nhm->nh_flags, fbuf, sizeof(fbuf)));
|
|
nlnh_dump(nhm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*nhm)));
|
|
break;
|
|
|
|
case RTM_NEWTUNNEL:
|
|
case RTM_DELTUNNEL:
|
|
case RTM_GETTUNNEL:
|
|
tnlm = NLMSG_DATA(nlmsg);
|
|
zlog_debug(" tnlm [family=(%d) %s ifindex=%d ", tnlm->family,
|
|
af_type2str(tnlm->family), tnlm->ifindex);
|
|
nltnl_dump(tnlm,
|
|
nlmsg->nlmsg_len -
|
|
NLMSG_LENGTH(sizeof(struct tunnel_msg)));
|
|
break;
|
|
|
|
|
|
case RTM_NEWNETCONF:
|
|
case RTM_DELNETCONF:
|
|
ncm = NLMSG_DATA(nlmsg);
|
|
zlog_debug(" ncm [family=%s (%d)]",
|
|
af_type2str(ncm->ncm_family), ncm->ncm_family);
|
|
nlncm_dump(ncm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ncm)));
|
|
break;
|
|
|
|
case RTM_NEWQDISC:
|
|
case RTM_DELQDISC:
|
|
case RTM_NEWTCLASS:
|
|
case RTM_DELTCLASS:
|
|
case RTM_NEWTFILTER:
|
|
case RTM_DELTFILTER:
|
|
tcm = NLMSG_DATA(nlmsg);
|
|
zlog_debug(
|
|
" tcm [type=%s family=%s (%d) ifindex=%d handle=%04x:%04x]",
|
|
tcm_nltype2str(nlmsg->nlmsg_type),
|
|
af_type2str(tcm->tcm_family), tcm->tcm_family,
|
|
tcm->tcm_ifindex, tcm->tcm_handle >> 16,
|
|
tcm->tcm_handle & 0xffff);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Try to get the next header. There should only be more
|
|
* messages if this header was flagged as MULTI, otherwise just
|
|
* end it here.
|
|
*/
|
|
nlmsg = NLMSG_NEXT(nlmsg, msglen);
|
|
if (NLMSG_OK(nlmsg, msglen) == 0)
|
|
return;
|
|
|
|
goto next_header;
|
|
}
|
|
|
|
#endif /* NETLINK_DEBUG */
|