]> git.proxmox.com Git - mirror_frr.git/blame - nhrpd/netlink_arp.c
nhrp: avoid crashing when terminating interface contexts
[mirror_frr.git] / nhrpd / netlink_arp.c
CommitLineData
2fb975da
TT
1/* NHRP netlink/neighbor table arpd code
2 * Copyright (c) 2014-2016 Timo Teräs
3 *
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.
8 */
9
b45ac5f5
DL
10#ifdef HAVE_CONFIG_H
11#include "config.h"
12#endif
13
2fb975da
TT
14#include <fcntl.h>
15#include <net/if.h>
16#include <netinet/if_ether.h>
17#include <linux/netlink.h>
18#include <linux/neighbour.h>
19#include <linux/netfilter/nfnetlink_log.h>
20
21#include "thread.h"
b3b75104
PG
22#include "stream.h"
23#include "prefix.h"
2fb975da
TT
24#include "nhrpd.h"
25#include "netlink.h"
26#include "znl.h"
27
28int netlink_req_fd = -1;
29int netlink_nflog_group;
30static int netlink_log_fd = -1;
31static struct thread *netlink_log_thread;
2fb975da
TT
32typedef void (*netlink_dispatch_f)(struct nlmsghdr *msg, struct zbuf *zb);
33
996c9314
LB
34void netlink_update_binding(struct interface *ifp, union sockunion *proto,
35 union sockunion *nbma)
2fb975da 36{
05657ec2 37 nhrp_send_zebra_nbr(proto, nbma, ifp);
2fb975da
TT
38}
39
2fb975da
TT
40static void netlink_log_register(int fd, int group)
41{
42 struct nlmsghdr *n;
43 struct nfgenmsg *nf;
44 struct nfulnl_msg_config_cmd cmd;
45 struct zbuf *zb = zbuf_alloc(512);
46
996c9314
LB
47 n = znl_nlmsg_push(zb, (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG,
48 NLM_F_REQUEST | NLM_F_ACK);
2fb975da 49 nf = znl_push(zb, sizeof(*nf));
996c9314 50 *nf = (struct nfgenmsg){
2fb975da
TT
51 .nfgen_family = AF_UNSPEC,
52 .version = NFNETLINK_V0,
53 .res_id = htons(group),
54 };
55 cmd.command = NFULNL_CFG_CMD_BIND;
56 znl_rta_push(zb, NFULA_CFG_CMD, &cmd, sizeof(cmd));
57 znl_nlmsg_complete(zb, n);
58
59 zbuf_send(zb, fd);
60 zbuf_free(zb);
61}
62
63static void netlink_log_indication(struct nlmsghdr *msg, struct zbuf *zb)
64{
65 struct nfgenmsg *nf;
66 struct rtattr *rta;
67 struct zbuf rtapl, pktpl;
68 struct interface *ifp;
69 struct nfulnl_msg_packet_hdr *pkthdr = NULL;
70 uint32_t *in_ndx = NULL;
71
72 nf = znl_pull(zb, sizeof(*nf));
996c9314
LB
73 if (!nf)
74 return;
2fb975da
TT
75
76 memset(&pktpl, 0, sizeof(pktpl));
77 while ((rta = znl_rta_pull(zb, &rtapl)) != NULL) {
78 switch (rta->rta_type) {
79 case NFULA_PACKET_HDR:
80 pkthdr = znl_pull(&rtapl, sizeof(*pkthdr));
81 break;
82 case NFULA_IFINDEX_INDEV:
83 in_ndx = znl_pull(&rtapl, sizeof(*in_ndx));
84 break;
85 case NFULA_PAYLOAD:
86 pktpl = rtapl;
87 break;
996c9314
LB
88 /* NFULA_HWHDR exists and is supposed to contain source
89 * hardware address. However, for ip_gre it seems to be
90 * the nexthop destination address if the packet matches
91 * route. */
2fb975da
TT
92 }
93 }
94
95 if (!pkthdr || !in_ndx || !zbuf_used(&pktpl))
96 return;
97
7e2b7603 98 ifp = if_lookup_by_index(htonl(*in_ndx), VRF_DEFAULT);
2fb975da
TT
99 if (!ifp)
100 return;
101
102 nhrp_peer_send_indication(ifp, htons(pkthdr->hw_protocol), &pktpl);
103}
104
105static int netlink_log_recv(struct thread *t)
106{
107 uint8_t buf[ZNL_BUFFER_SIZE];
108 int fd = THREAD_FD(t);
109 struct zbuf payload, zb;
110 struct nlmsghdr *n;
111
112 netlink_log_thread = NULL;
113
114 zbuf_init(&zb, buf, sizeof(buf), 0);
115 while (zbuf_recv(&zb, fd) > 0) {
831600c3 116 while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) {
996c9314
LB
117 debugf(NHRP_DEBUG_KERNEL,
118 "Netlink-log: Received msg_type %u, msg_flags %u",
119 n->nlmsg_type, n->nlmsg_flags);
2fb975da 120 switch (n->nlmsg_type) {
996c9314 121 case (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_PACKET:
2fb975da
TT
122 netlink_log_indication(n, &payload);
123 break;
124 }
125 }
126 }
127
ffa2c898
QY
128 thread_add_read(master, netlink_log_recv, 0, netlink_log_fd,
129 &netlink_log_thread);
2fb975da
TT
130
131 return 0;
132}
133
134void netlink_set_nflog_group(int nlgroup)
135{
136 if (netlink_log_fd >= 0) {
50478845 137 thread_cancel(&netlink_log_thread);
2fb975da
TT
138 close(netlink_log_fd);
139 netlink_log_fd = -1;
140 }
141 netlink_nflog_group = nlgroup;
142 if (nlgroup) {
996c9314 143 netlink_log_fd = znl_open(NETLINK_NETFILTER, 0);
6c8ca260
JB
144 if (netlink_log_fd < 0)
145 return;
146
2fb975da 147 netlink_log_register(netlink_log_fd, nlgroup);
ffa2c898
QY
148 thread_add_read(master, netlink_log_recv, 0, netlink_log_fd,
149 &netlink_log_thread);
2fb975da
TT
150 }
151}
152
b3b75104
PG
153void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS)
154{
155 union sockunion addr = {}, lladdr = {};
156 struct interface *ifp;
157 ifindex_t idx;
158 struct ethaddr mac;
159 int state, ndm_state;
160 struct nhrp_cache *c;
161 unsigned short l2_len;
162
163 STREAM_GETL(zclient->ibuf, idx);
164 ifp = if_lookup_by_index(idx, vrf_id);
165 STREAM_GETW(zclient->ibuf, addr.sa.sa_family);
166 if (addr.sa.sa_family == AF_INET) {
167 STREAM_GET(&addr.sin.sin_addr.s_addr,
168 zclient->ibuf, IPV4_MAX_BYTELEN);
169 } else {
170 STREAM_GET(&addr.sin6.sin6_addr.s6_addr,
171 zclient->ibuf, IPV6_MAX_BYTELEN);
172 }
173 STREAM_GETL(zclient->ibuf, ndm_state);
174
175 STREAM_GETL(zclient->ibuf, l2_len);
176 if (l2_len) {
177 STREAM_GET(&mac, zclient->ibuf, l2_len);
178 if (l2_len == IPV4_MAX_BYTELEN)
179 sockunion_set(&lladdr, AF_INET, (const uint8_t *)&mac,
180 l2_len);
181 }
182 if (!ifp)
183 return;
184 c = nhrp_cache_get(ifp, &addr, 0);
185 if (!c)
186 return;
187 debugf(NHRP_DEBUG_KERNEL,
188 "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u",
189 (cmd == ZEBRA_NHRP_NEIGH_GET)
190 ? "who-has"
191 : (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? "new-neigh"
192 : "del-neigh",
193 &addr, ifp->name, &lladdr, ndm_state, c->used, c->cur.type);
194 if (cmd == ZEBRA_NHRP_NEIGH_GET) {
195 if (c->cur.type >= NHRP_CACHE_CACHED) {
196 nhrp_cache_set_used(c, 1);
197 debugf(NHRP_DEBUG_KERNEL,
198 "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
199 &addr, ifp->name, &c->cur.remote_nbma_natoa,
200 &c->cur.peer->vc->remote.nbma, &lladdr);
201 /* In case of shortcuts, nbma is given by lladdr, not
202 * vc->remote.nbma.
203 */
204 netlink_update_binding(ifp, &addr, &lladdr);
205 }
206 } else {
207 state = (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? ndm_state
208 : NUD_FAILED;
209 nhrp_cache_set_used(c, state == NUD_REACHABLE);
210 }
211 return;
212 stream_failure:
213 return;
214}
215
6c8ca260 216void netlink_init(void)
2fb975da
TT
217{
218 netlink_req_fd = znl_open(NETLINK_ROUTE, 0);
6c8ca260
JB
219 if (netlink_req_fd < 0)
220 return;
2fb975da 221}