1 /* NHRP netlink/neighbor table arpd code
2 * Copyright (c) 2014-2016 Timo Teräs
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
16 #include <netinet/if_ether.h>
17 #include <linux/netlink.h>
18 #include <linux/neighbour.h>
19 #include <linux/netfilter/nfnetlink_log.h>
28 int netlink_req_fd
= -1;
29 int netlink_nflog_group
;
30 static int netlink_log_fd
= -1;
31 static struct thread
*netlink_log_thread
;
33 void netlink_update_binding(struct interface
*ifp
, union sockunion
*proto
,
34 union sockunion
*nbma
)
36 nhrp_send_zebra_nbr(proto
, nbma
, ifp
);
39 static void netlink_log_register(int fd
, int group
)
43 struct nfulnl_msg_config_cmd cmd
;
44 struct zbuf
*zb
= zbuf_alloc(512);
46 n
= znl_nlmsg_push(zb
, (NFNL_SUBSYS_ULOG
<< 8) | NFULNL_MSG_CONFIG
,
47 NLM_F_REQUEST
| NLM_F_ACK
);
48 nf
= znl_push(zb
, sizeof(*nf
));
49 *nf
= (struct nfgenmsg
){
50 .nfgen_family
= AF_UNSPEC
,
51 .version
= NFNETLINK_V0
,
52 .res_id
= htons(group
),
54 cmd
.command
= NFULNL_CFG_CMD_BIND
;
55 znl_rta_push(zb
, NFULA_CFG_CMD
, &cmd
, sizeof(cmd
));
56 znl_nlmsg_complete(zb
, n
);
62 static void netlink_log_indication(struct nlmsghdr
*msg
, struct zbuf
*zb
)
66 struct zbuf rtapl
, pktpl
;
67 struct interface
*ifp
;
68 struct nfulnl_msg_packet_hdr
*pkthdr
= NULL
;
69 uint32_t *in_ndx
= NULL
;
71 nf
= znl_pull(zb
, sizeof(*nf
));
75 memset(&pktpl
, 0, sizeof(pktpl
));
76 while ((rta
= znl_rta_pull(zb
, &rtapl
)) != NULL
) {
77 switch (rta
->rta_type
) {
78 case NFULA_PACKET_HDR
:
79 pkthdr
= znl_pull(&rtapl
, sizeof(*pkthdr
));
81 case NFULA_IFINDEX_INDEV
:
82 in_ndx
= znl_pull(&rtapl
, sizeof(*in_ndx
));
87 /* NFULA_HWHDR exists and is supposed to contain source
88 * hardware address. However, for ip_gre it seems to be
89 * the nexthop destination address if the packet matches
94 if (!pkthdr
|| !in_ndx
|| !zbuf_used(&pktpl
))
97 ifp
= if_lookup_by_index(htonl(*in_ndx
), VRF_DEFAULT
);
101 nhrp_peer_send_indication(ifp
, htons(pkthdr
->hw_protocol
), &pktpl
);
104 static int netlink_log_recv(struct thread
*t
)
106 uint8_t buf
[ZNL_BUFFER_SIZE
];
107 int fd
= THREAD_FD(t
);
108 struct zbuf payload
, zb
;
111 netlink_log_thread
= NULL
;
113 zbuf_init(&zb
, buf
, sizeof(buf
), 0);
114 while (zbuf_recv(&zb
, fd
) > 0) {
115 while ((n
= znl_nlmsg_pull(&zb
, &payload
)) != NULL
) {
116 debugf(NHRP_DEBUG_KERNEL
,
117 "Netlink-log: Received msg_type %u, msg_flags %u",
118 n
->nlmsg_type
, n
->nlmsg_flags
);
119 switch (n
->nlmsg_type
) {
120 case (NFNL_SUBSYS_ULOG
<< 8) | NFULNL_MSG_PACKET
:
121 netlink_log_indication(n
, &payload
);
127 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
128 &netlink_log_thread
);
133 void netlink_set_nflog_group(int nlgroup
)
135 if (netlink_log_fd
>= 0) {
136 thread_cancel(&netlink_log_thread
);
137 close(netlink_log_fd
);
140 netlink_nflog_group
= nlgroup
;
142 netlink_log_fd
= znl_open(NETLINK_NETFILTER
, 0);
143 if (netlink_log_fd
< 0)
146 netlink_log_register(netlink_log_fd
, nlgroup
);
147 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
148 &netlink_log_thread
);
152 void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS
)
154 union sockunion addr
= {}, lladdr
= {};
155 struct interface
*ifp
;
156 int state
, ndm_state
;
157 struct nhrp_cache
*c
;
158 struct zapi_neigh_ip api
= {};
160 zclient_neigh_ip_decode(zclient
->ibuf
, &api
);
161 if (api
.ip_in
.ipa_type
== AF_UNSPEC
)
163 sockunion_family(&addr
) = api
.ip_in
.ipa_type
;
164 memcpy((uint8_t *)sockunion_get_addr(&addr
), &api
.ip_in
.ip
.addr
,
165 family2addrsize(api
.ip_in
.ipa_type
));
167 sockunion_family(&lladdr
) = api
.ip_out
.ipa_type
;
168 if (api
.ip_out
.ipa_type
!= AF_UNSPEC
)
169 memcpy((uint8_t *)sockunion_get_addr(&lladdr
),
171 family2addrsize(api
.ip_out
.ipa_type
));
173 ifp
= if_lookup_by_index(api
.index
, vrf_id
);
174 ndm_state
= api
.ndm_state
;
178 c
= nhrp_cache_get(ifp
, &addr
, 0);
181 debugf(NHRP_DEBUG_KERNEL
,
182 "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u",
183 (cmd
== ZEBRA_NHRP_NEIGH_GET
)
185 : (cmd
== ZEBRA_NHRP_NEIGH_ADDED
) ? "new-neigh"
187 &addr
, ifp
->name
, &lladdr
, ndm_state
, c
->used
, c
->cur
.type
);
188 if (cmd
== ZEBRA_NHRP_NEIGH_GET
) {
189 if (c
->cur
.type
>= NHRP_CACHE_CACHED
) {
190 nhrp_cache_set_used(c
, 1);
191 debugf(NHRP_DEBUG_KERNEL
,
192 "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
193 &addr
, ifp
->name
, &c
->cur
.remote_nbma_natoa
,
194 &c
->cur
.peer
->vc
->remote
.nbma
, &lladdr
);
195 /* In case of shortcuts, nbma is given by lladdr, not
198 netlink_update_binding(ifp
, &addr
, &lladdr
);
201 state
= (cmd
== ZEBRA_NHRP_NEIGH_ADDED
) ? ndm_state
202 : ZEBRA_NEIGH_STATE_FAILED
;
203 nhrp_cache_set_used(c
, state
== ZEBRA_NEIGH_STATE_REACHABLE
);
207 void netlink_init(void)
209 netlink_req_fd
= znl_open(NETLINK_ROUTE
, 0);
210 if (netlink_req_fd
< 0)