1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* NHRP netlink/neighbor table arpd code
3 * Copyright (c) 2014-2016 Timo Teräs
12 #include <netinet/if_ether.h>
13 #include <linux/netlink.h>
14 #include <linux/neighbour.h>
15 #include <linux/netfilter/nfnetlink_log.h>
24 int netlink_nflog_group
;
25 static int netlink_log_fd
= -1;
26 static struct thread
*netlink_log_thread
;
28 void netlink_update_binding(struct interface
*ifp
, union sockunion
*proto
,
29 union sockunion
*nbma
)
31 nhrp_send_zebra_nbr(proto
, nbma
, ifp
);
34 static void netlink_log_register(int fd
, int group
)
38 struct nfulnl_msg_config_cmd cmd
;
39 struct zbuf
*zb
= zbuf_alloc(512);
41 n
= znl_nlmsg_push(zb
, (NFNL_SUBSYS_ULOG
<< 8) | NFULNL_MSG_CONFIG
,
42 NLM_F_REQUEST
| NLM_F_ACK
);
43 nf
= znl_push(zb
, sizeof(*nf
));
44 *nf
= (struct nfgenmsg
){
45 .nfgen_family
= AF_UNSPEC
,
46 .version
= NFNETLINK_V0
,
47 .res_id
= htons(group
),
49 cmd
.command
= NFULNL_CFG_CMD_BIND
;
50 znl_rta_push(zb
, NFULA_CFG_CMD
, &cmd
, sizeof(cmd
));
51 znl_nlmsg_complete(zb
, n
);
57 static void netlink_log_indication(struct nlmsghdr
*msg
, struct zbuf
*zb
)
61 struct zbuf rtapl
, pktpl
;
62 struct interface
*ifp
;
63 struct nfulnl_msg_packet_hdr
*pkthdr
= NULL
;
64 uint32_t *in_ndx
= NULL
;
66 nf
= znl_pull(zb
, sizeof(*nf
));
70 memset(&pktpl
, 0, sizeof(pktpl
));
71 while ((rta
= znl_rta_pull(zb
, &rtapl
)) != NULL
) {
72 switch (rta
->rta_type
) {
73 case NFULA_PACKET_HDR
:
74 pkthdr
= znl_pull(&rtapl
, sizeof(*pkthdr
));
76 case NFULA_IFINDEX_INDEV
:
77 in_ndx
= znl_pull(&rtapl
, sizeof(*in_ndx
));
82 /* NFULA_HWHDR exists and is supposed to contain source
83 * hardware address. However, for ip_gre it seems to be
84 * the nexthop destination address if the packet matches
89 if (!pkthdr
|| !in_ndx
|| !zbuf_used(&pktpl
))
92 ifp
= if_lookup_by_index(htonl(*in_ndx
), VRF_DEFAULT
);
96 nhrp_peer_send_indication(ifp
, htons(pkthdr
->hw_protocol
), &pktpl
);
99 static void netlink_log_recv(struct thread
*t
)
101 uint8_t buf
[ZNL_BUFFER_SIZE
];
102 int fd
= THREAD_FD(t
);
103 struct zbuf payload
, zb
;
107 zbuf_init(&zb
, buf
, sizeof(buf
), 0);
108 while (zbuf_recv(&zb
, fd
) > 0) {
109 while ((n
= znl_nlmsg_pull(&zb
, &payload
)) != NULL
) {
110 debugf(NHRP_DEBUG_KERNEL
,
111 "Netlink-log: Received msg_type %u, msg_flags %u",
112 n
->nlmsg_type
, n
->nlmsg_flags
);
113 switch (n
->nlmsg_type
) {
114 case (NFNL_SUBSYS_ULOG
<< 8) | NFULNL_MSG_PACKET
:
115 netlink_log_indication(n
, &payload
);
121 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
122 &netlink_log_thread
);
125 void netlink_set_nflog_group(int nlgroup
)
127 if (netlink_log_fd
>= 0) {
128 thread_cancel(&netlink_log_thread
);
129 close(netlink_log_fd
);
132 netlink_nflog_group
= nlgroup
;
134 netlink_log_fd
= znl_open(NETLINK_NETFILTER
, 0);
135 if (netlink_log_fd
< 0)
138 netlink_log_register(netlink_log_fd
, nlgroup
);
139 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
140 &netlink_log_thread
);
144 int nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS
)
146 union sockunion addr
= {}, lladdr
= {};
147 struct interface
*ifp
;
148 int state
, ndm_state
;
149 struct nhrp_cache
*c
;
150 struct zapi_neigh_ip api
= {};
152 zclient_neigh_ip_decode(zclient
->ibuf
, &api
);
153 if (api
.ip_in
.ipa_type
== AF_UNSPEC
)
155 sockunion_family(&addr
) = api
.ip_in
.ipa_type
;
156 memcpy((uint8_t *)sockunion_get_addr(&addr
), &api
.ip_in
.ip
.addr
,
157 family2addrsize(api
.ip_in
.ipa_type
));
159 sockunion_family(&lladdr
) = api
.ip_out
.ipa_type
;
160 if (api
.ip_out
.ipa_type
!= AF_UNSPEC
)
161 memcpy((uint8_t *)sockunion_get_addr(&lladdr
),
163 family2addrsize(api
.ip_out
.ipa_type
));
165 ifp
= if_lookup_by_index(api
.index
, vrf_id
);
166 ndm_state
= api
.ndm_state
;
170 c
= nhrp_cache_get(ifp
, &addr
, 0);
173 debugf(NHRP_DEBUG_KERNEL
,
174 "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u",
175 (cmd
== ZEBRA_NHRP_NEIGH_GET
)
177 : (cmd
== ZEBRA_NHRP_NEIGH_ADDED
) ? "new-neigh"
179 &addr
, ifp
->name
, &lladdr
, ndm_state
, c
->used
, c
->cur
.type
);
180 if (cmd
== ZEBRA_NHRP_NEIGH_GET
) {
181 if (c
->cur
.type
>= NHRP_CACHE_CACHED
) {
182 nhrp_cache_set_used(c
, 1);
183 debugf(NHRP_DEBUG_KERNEL
,
184 "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
185 &addr
, ifp
->name
, &c
->cur
.remote_nbma_natoa
,
186 &c
->cur
.peer
->vc
->remote
.nbma
, &lladdr
);
187 /* In case of shortcuts, nbma is given by lladdr, not
190 netlink_update_binding(ifp
, &addr
, &lladdr
);
193 state
= (cmd
== ZEBRA_NHRP_NEIGH_ADDED
) ? ndm_state
194 : ZEBRA_NEIGH_STATE_FAILED
;
195 nhrp_cache_set_used(c
, state
== ZEBRA_NEIGH_STATE_REACHABLE
);