]> git.proxmox.com Git - mirror_frr.git/blame - nhrpd/netlink_arp.c
*: manual SPDX License ID conversions
[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
2fb975da
TT
28int netlink_nflog_group;
29static int netlink_log_fd = -1;
30static struct thread *netlink_log_thread;
2fb975da 31
996c9314
LB
32void netlink_update_binding(struct interface *ifp, union sockunion *proto,
33 union sockunion *nbma)
2fb975da 34{
05657ec2 35 nhrp_send_zebra_nbr(proto, nbma, ifp);
2fb975da
TT
36}
37
2fb975da
TT
38static void netlink_log_register(int fd, int group)
39{
40 struct nlmsghdr *n;
41 struct nfgenmsg *nf;
42 struct nfulnl_msg_config_cmd cmd;
43 struct zbuf *zb = zbuf_alloc(512);
44
996c9314
LB
45 n = znl_nlmsg_push(zb, (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG,
46 NLM_F_REQUEST | NLM_F_ACK);
2fb975da 47 nf = znl_push(zb, sizeof(*nf));
996c9314 48 *nf = (struct nfgenmsg){
2fb975da
TT
49 .nfgen_family = AF_UNSPEC,
50 .version = NFNETLINK_V0,
51 .res_id = htons(group),
52 };
53 cmd.command = NFULNL_CFG_CMD_BIND;
54 znl_rta_push(zb, NFULA_CFG_CMD, &cmd, sizeof(cmd));
55 znl_nlmsg_complete(zb, n);
56
57 zbuf_send(zb, fd);
58 zbuf_free(zb);
59}
60
61static void netlink_log_indication(struct nlmsghdr *msg, struct zbuf *zb)
62{
63 struct nfgenmsg *nf;
64 struct rtattr *rta;
65 struct zbuf rtapl, pktpl;
66 struct interface *ifp;
67 struct nfulnl_msg_packet_hdr *pkthdr = NULL;
68 uint32_t *in_ndx = NULL;
69
70 nf = znl_pull(zb, sizeof(*nf));
996c9314
LB
71 if (!nf)
72 return;
2fb975da
TT
73
74 memset(&pktpl, 0, sizeof(pktpl));
75 while ((rta = znl_rta_pull(zb, &rtapl)) != NULL) {
76 switch (rta->rta_type) {
77 case NFULA_PACKET_HDR:
78 pkthdr = znl_pull(&rtapl, sizeof(*pkthdr));
79 break;
80 case NFULA_IFINDEX_INDEV:
81 in_ndx = znl_pull(&rtapl, sizeof(*in_ndx));
82 break;
83 case NFULA_PAYLOAD:
84 pktpl = rtapl;
85 break;
996c9314
LB
86 /* NFULA_HWHDR exists and is supposed to contain source
87 * hardware address. However, for ip_gre it seems to be
88 * the nexthop destination address if the packet matches
89 * route. */
2fb975da
TT
90 }
91 }
92
93 if (!pkthdr || !in_ndx || !zbuf_used(&pktpl))
94 return;
95
7e2b7603 96 ifp = if_lookup_by_index(htonl(*in_ndx), VRF_DEFAULT);
2fb975da
TT
97 if (!ifp)
98 return;
99
100 nhrp_peer_send_indication(ifp, htons(pkthdr->hw_protocol), &pktpl);
101}
102
cc9f21da 103static void netlink_log_recv(struct thread *t)
2fb975da
TT
104{
105 uint8_t buf[ZNL_BUFFER_SIZE];
106 int fd = THREAD_FD(t);
107 struct zbuf payload, zb;
108 struct nlmsghdr *n;
109
2fb975da
TT
110
111 zbuf_init(&zb, buf, sizeof(buf), 0);
112 while (zbuf_recv(&zb, fd) > 0) {
831600c3 113 while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) {
996c9314
LB
114 debugf(NHRP_DEBUG_KERNEL,
115 "Netlink-log: Received msg_type %u, msg_flags %u",
116 n->nlmsg_type, n->nlmsg_flags);
2fb975da 117 switch (n->nlmsg_type) {
996c9314 118 case (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_PACKET:
2fb975da
TT
119 netlink_log_indication(n, &payload);
120 break;
121 }
122 }
123 }
124
ffa2c898
QY
125 thread_add_read(master, netlink_log_recv, 0, netlink_log_fd,
126 &netlink_log_thread);
2fb975da
TT
127}
128
129void netlink_set_nflog_group(int nlgroup)
130{
131 if (netlink_log_fd >= 0) {
50478845 132 thread_cancel(&netlink_log_thread);
2fb975da
TT
133 close(netlink_log_fd);
134 netlink_log_fd = -1;
135 }
136 netlink_nflog_group = nlgroup;
137 if (nlgroup) {
996c9314 138 netlink_log_fd = znl_open(NETLINK_NETFILTER, 0);
6c8ca260
JB
139 if (netlink_log_fd < 0)
140 return;
141
2fb975da 142 netlink_log_register(netlink_log_fd, nlgroup);
ffa2c898
QY
143 thread_add_read(master, netlink_log_recv, 0, netlink_log_fd,
144 &netlink_log_thread);
2fb975da
TT
145 }
146}
147
a243d1db 148int nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS)
b3b75104
PG
149{
150 union sockunion addr = {}, lladdr = {};
151 struct interface *ifp;
b3b75104
PG
152 int state, ndm_state;
153 struct nhrp_cache *c;
d603c077
PG
154 struct zapi_neigh_ip api = {};
155
156 zclient_neigh_ip_decode(zclient->ibuf, &api);
157 if (api.ip_in.ipa_type == AF_UNSPEC)
a243d1db 158 return 0;
d603c077
PG
159 sockunion_family(&addr) = api.ip_in.ipa_type;
160 memcpy((uint8_t *)sockunion_get_addr(&addr), &api.ip_in.ip.addr,
161 family2addrsize(api.ip_in.ipa_type));
162
163 sockunion_family(&lladdr) = api.ip_out.ipa_type;
164 if (api.ip_out.ipa_type != AF_UNSPEC)
165 memcpy((uint8_t *)sockunion_get_addr(&lladdr),
166 &api.ip_out.ip.addr,
167 family2addrsize(api.ip_out.ipa_type));
168
169 ifp = if_lookup_by_index(api.index, vrf_id);
170 ndm_state = api.ndm_state;
171
b3b75104 172 if (!ifp)
a243d1db 173 return 0;
b3b75104
PG
174 c = nhrp_cache_get(ifp, &addr, 0);
175 if (!c)
a243d1db 176 return 0;
b3b75104
PG
177 debugf(NHRP_DEBUG_KERNEL,
178 "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u",
179 (cmd == ZEBRA_NHRP_NEIGH_GET)
180 ? "who-has"
181 : (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? "new-neigh"
182 : "del-neigh",
183 &addr, ifp->name, &lladdr, ndm_state, c->used, c->cur.type);
184 if (cmd == ZEBRA_NHRP_NEIGH_GET) {
185 if (c->cur.type >= NHRP_CACHE_CACHED) {
186 nhrp_cache_set_used(c, 1);
187 debugf(NHRP_DEBUG_KERNEL,
188 "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
189 &addr, ifp->name, &c->cur.remote_nbma_natoa,
190 &c->cur.peer->vc->remote.nbma, &lladdr);
191 /* In case of shortcuts, nbma is given by lladdr, not
192 * vc->remote.nbma.
193 */
194 netlink_update_binding(ifp, &addr, &lladdr);
195 }
196 } else {
197 state = (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? ndm_state
d603c077
PG
198 : ZEBRA_NEIGH_STATE_FAILED;
199 nhrp_cache_set_used(c, state == ZEBRA_NEIGH_STATE_REACHABLE);
b3b75104 200 }
a243d1db 201 return 0;
b3b75104 202}