]> git.proxmox.com Git - mirror_frr.git/blob - nhrpd/netlink_arp.c
Merge pull request #9649 from proelbtn/add-support-for-end-dt4
[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_nflog_group;
29 static int netlink_log_fd = -1;
30 static struct thread *netlink_log_thread;
31
32 void netlink_update_binding(struct interface *ifp, union sockunion *proto,
33 union sockunion *nbma)
34 {
35 nhrp_send_zebra_nbr(proto, nbma, ifp);
36 }
37
38 static 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
45 n = znl_nlmsg_push(zb, (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG,
46 NLM_F_REQUEST | NLM_F_ACK);
47 nf = znl_push(zb, sizeof(*nf));
48 *nf = (struct nfgenmsg){
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
61 static 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));
71 if (!nf)
72 return;
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;
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. */
90 }
91 }
92
93 if (!pkthdr || !in_ndx || !zbuf_used(&pktpl))
94 return;
95
96 ifp = if_lookup_by_index(htonl(*in_ndx), VRF_DEFAULT);
97 if (!ifp)
98 return;
99
100 nhrp_peer_send_indication(ifp, htons(pkthdr->hw_protocol), &pktpl);
101 }
102
103 static int netlink_log_recv(struct thread *t)
104 {
105 uint8_t buf[ZNL_BUFFER_SIZE];
106 int fd = THREAD_FD(t);
107 struct zbuf payload, zb;
108 struct nlmsghdr *n;
109
110
111 zbuf_init(&zb, buf, sizeof(buf), 0);
112 while (zbuf_recv(&zb, fd) > 0) {
113 while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) {
114 debugf(NHRP_DEBUG_KERNEL,
115 "Netlink-log: Received msg_type %u, msg_flags %u",
116 n->nlmsg_type, n->nlmsg_flags);
117 switch (n->nlmsg_type) {
118 case (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_PACKET:
119 netlink_log_indication(n, &payload);
120 break;
121 }
122 }
123 }
124
125 thread_add_read(master, netlink_log_recv, 0, netlink_log_fd,
126 &netlink_log_thread);
127
128 return 0;
129 }
130
131 void netlink_set_nflog_group(int nlgroup)
132 {
133 if (netlink_log_fd >= 0) {
134 thread_cancel(&netlink_log_thread);
135 close(netlink_log_fd);
136 netlink_log_fd = -1;
137 }
138 netlink_nflog_group = nlgroup;
139 if (nlgroup) {
140 netlink_log_fd = znl_open(NETLINK_NETFILTER, 0);
141 if (netlink_log_fd < 0)
142 return;
143
144 netlink_log_register(netlink_log_fd, nlgroup);
145 thread_add_read(master, netlink_log_recv, 0, netlink_log_fd,
146 &netlink_log_thread);
147 }
148 }
149
150 int nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS)
151 {
152 union sockunion addr = {}, lladdr = {};
153 struct interface *ifp;
154 int state, ndm_state;
155 struct nhrp_cache *c;
156 struct zapi_neigh_ip api = {};
157
158 zclient_neigh_ip_decode(zclient->ibuf, &api);
159 if (api.ip_in.ipa_type == AF_UNSPEC)
160 return 0;
161 sockunion_family(&addr) = api.ip_in.ipa_type;
162 memcpy((uint8_t *)sockunion_get_addr(&addr), &api.ip_in.ip.addr,
163 family2addrsize(api.ip_in.ipa_type));
164
165 sockunion_family(&lladdr) = api.ip_out.ipa_type;
166 if (api.ip_out.ipa_type != AF_UNSPEC)
167 memcpy((uint8_t *)sockunion_get_addr(&lladdr),
168 &api.ip_out.ip.addr,
169 family2addrsize(api.ip_out.ipa_type));
170
171 ifp = if_lookup_by_index(api.index, vrf_id);
172 ndm_state = api.ndm_state;
173
174 if (!ifp)
175 return 0;
176 c = nhrp_cache_get(ifp, &addr, 0);
177 if (!c)
178 return 0;
179 debugf(NHRP_DEBUG_KERNEL,
180 "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u",
181 (cmd == ZEBRA_NHRP_NEIGH_GET)
182 ? "who-has"
183 : (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? "new-neigh"
184 : "del-neigh",
185 &addr, ifp->name, &lladdr, ndm_state, c->used, c->cur.type);
186 if (cmd == ZEBRA_NHRP_NEIGH_GET) {
187 if (c->cur.type >= NHRP_CACHE_CACHED) {
188 nhrp_cache_set_used(c, 1);
189 debugf(NHRP_DEBUG_KERNEL,
190 "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
191 &addr, ifp->name, &c->cur.remote_nbma_natoa,
192 &c->cur.peer->vc->remote.nbma, &lladdr);
193 /* In case of shortcuts, nbma is given by lladdr, not
194 * vc->remote.nbma.
195 */
196 netlink_update_binding(ifp, &addr, &lladdr);
197 }
198 } else {
199 state = (cmd == ZEBRA_NHRP_NEIGH_ADDED) ? ndm_state
200 : ZEBRA_NEIGH_STATE_FAILED;
201 nhrp_cache_set_used(c, state == ZEBRA_NEIGH_STATE_REACHABLE);
202 }
203 return 0;
204 }