]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/netlink_arp.c
Merge pull request #8488 from mjstapp/more_workqueue
[mirror_frr.git] / nhrpd / netlink_arp.c
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
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13
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"
22 #include "stream.h"
23 #include "prefix.h"
24 #include "nhrpd.h"
25 #include "netlink.h"
26 #include "znl.h"
27
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;
32
33 void netlink_update_binding(struct interface *ifp, union sockunion *proto,
34 union sockunion *nbma)
35 {
36 nhrp_send_zebra_nbr(proto, nbma, ifp);
37 }
38
39 static void netlink_log_register(int fd, int group)
40 {
41 struct nlmsghdr *n;
42 struct nfgenmsg *nf;
43 struct nfulnl_msg_config_cmd cmd;
44 struct zbuf *zb = zbuf_alloc(512);
45
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),
53 };
54 cmd.command = NFULNL_CFG_CMD_BIND;
55 znl_rta_push(zb, NFULA_CFG_CMD, &cmd, sizeof(cmd));
56 znl_nlmsg_complete(zb, n);
57
58 zbuf_send(zb, fd);
59 zbuf_free(zb);
60 }
61
62 static void netlink_log_indication(struct nlmsghdr *msg, struct zbuf *zb)
63 {
64 struct nfgenmsg *nf;
65 struct rtattr *rta;
66 struct zbuf rtapl, pktpl;
67 struct interface *ifp;
68 struct nfulnl_msg_packet_hdr *pkthdr = NULL;
69 uint32_t *in_ndx = NULL;
70
71 nf = znl_pull(zb, sizeof(*nf));
72 if (!nf)
73 return;
74
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));
80 break;
81 case NFULA_IFINDEX_INDEV:
82 in_ndx = znl_pull(&rtapl, sizeof(*in_ndx));
83 break;
84 case NFULA_PAYLOAD:
85 pktpl = rtapl;
86 break;
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
90 * route. */
91 }
92 }
93
94 if (!pkthdr || !in_ndx || !zbuf_used(&pktpl))
95 return;
96
97 ifp = if_lookup_by_index(htonl(*in_ndx), VRF_DEFAULT);
98 if (!ifp)
99 return;
100
101 nhrp_peer_send_indication(ifp, htons(pkthdr->hw_protocol), &pktpl);
102 }
103
104 static int netlink_log_recv(struct thread *t)
105 {
106 uint8_t buf[ZNL_BUFFER_SIZE];
107 int fd = THREAD_FD(t);
108 struct zbuf payload, zb;
109 struct nlmsghdr *n;
110
111 netlink_log_thread = NULL;
112
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);
122 break;
123 }
124 }
125 }
126
127 thread_add_read(master, netlink_log_recv, 0, netlink_log_fd,
128 &netlink_log_thread);
129
130 return 0;
131 }
132
133 void netlink_set_nflog_group(int nlgroup)
134 {
135 if (netlink_log_fd >= 0) {
136 thread_cancel(&netlink_log_thread);
137 close(netlink_log_fd);
138 netlink_log_fd = -1;
139 }
140 netlink_nflog_group = nlgroup;
141 if (nlgroup) {
142 netlink_log_fd = znl_open(NETLINK_NETFILTER, 0);
143 if (netlink_log_fd < 0)
144 return;
145
146 netlink_log_register(netlink_log_fd, nlgroup);
147 thread_add_read(master, netlink_log_recv, 0, netlink_log_fd,
148 &netlink_log_thread);
149 }
150 }
151
152 void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS)
153 {
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 = {};
159
160 zclient_neigh_ip_decode(zclient->ibuf, &api);
161 if (api.ip_in.ipa_type == AF_UNSPEC)
162 return;
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));
166
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),
170 &api.ip_out.ip.addr,
171 family2addrsize(api.ip_out.ipa_type));
172
173 ifp = if_lookup_by_index(api.index, vrf_id);
174 ndm_state = api.ndm_state;
175
176 if (!ifp)
177 return;
178 c = nhrp_cache_get(ifp, &addr, 0);
179 if (!c)
180 return;
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)
184 ? "who-has"
185 : (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? "new-neigh"
186 : "del-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
196 * vc->remote.nbma.
197 */
198 netlink_update_binding(ifp, &addr, &lladdr);
199 }
200 } else {
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);
204 }
205 }
206
207 void netlink_init(void)
208 {
209 netlink_req_fd = znl_open(NETLINK_ROUTE, 0);
210 if (netlink_req_fd < 0)
211 return;
212 }