source: src/router/quagga/nhrpd/netlink_arp.c @ 31640

Last change on this file since 31640 was 31640, checked in by brainslayer, 2 months ago

update quagga

File size: 7.0 KB
Line 
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#include <fcntl.h>
11#include <net/if.h>
12#include <netinet/if_ether.h>
13#include <linux/netlink.h>
14#include <linux/neighbour.h>
15#include <linux/netfilter/nfnetlink_log.h>
16
17#include "thread.h"
18#include "nhrpd.h"
19#include "netlink.h"
20#include "znl.h"
21
22int netlink_req_fd = -1;
23int netlink_nflog_group;
24static int netlink_log_fd = -1;
25static struct thread *netlink_log_thread;
26static int netlink_listen_fd = -1;
27
28typedef void (*netlink_dispatch_f)(struct nlmsghdr *msg, struct zbuf *zb);
29
30void netlink_update_binding(struct interface *ifp, union sockunion *proto, union sockunion *nbma)
31{
32        struct nlmsghdr *n;
33        struct ndmsg *ndm;
34        struct zbuf *zb = zbuf_alloc(512);
35
36        n = znl_nlmsg_push(zb, nbma ? RTM_NEWNEIGH : RTM_DELNEIGH, NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
37        ndm = znl_push(zb, sizeof(*ndm));
38        *ndm = (struct ndmsg) {
39                .ndm_family = sockunion_family(proto),
40                .ndm_ifindex = ifp->ifindex,
41                .ndm_type = RTN_UNICAST,
42                .ndm_state = nbma ? NUD_REACHABLE : NUD_FAILED,
43        };
44        znl_rta_push(zb, NDA_DST, sockunion_get_addr(proto), family2addrsize(sockunion_family(proto)));
45        if (nbma)
46                znl_rta_push(zb, NDA_LLADDR, sockunion_get_addr(nbma), family2addrsize(sockunion_family(nbma)));
47        znl_nlmsg_complete(zb, n);
48        zbuf_send(zb, netlink_req_fd);
49        zbuf_recv(zb, netlink_req_fd);
50        zbuf_free(zb);
51}
52
53static void netlink_neigh_msg(struct nlmsghdr *msg, struct zbuf *zb)
54{
55        struct ndmsg *ndm;
56        struct rtattr *rta;
57        struct nhrp_cache *c;
58        struct interface *ifp;
59        struct zbuf payload;
60        union sockunion addr;
61        size_t len;
62        char buf[SU_ADDRSTRLEN];
63        int state;
64
65        ndm = znl_pull(zb, sizeof(*ndm));
66        if (!ndm) return;
67
68        sockunion_family(&addr) = AF_UNSPEC;
69        while ((rta = znl_rta_pull(zb, &payload)) != NULL) {
70                len = zbuf_used(&payload);
71                switch (rta->rta_type) {
72                case NDA_DST:
73                        sockunion_set(&addr, ndm->ndm_family, zbuf_pulln(&payload, len), len);
74                        break;
75                }
76        }
77
78        ifp = if_lookup_by_index(ndm->ndm_ifindex);
79        if (!ifp || sockunion_family(&addr) == AF_UNSPEC)
80                return;
81
82        c = nhrp_cache_get(ifp, &addr, 0);
83        if (!c)
84                return;
85
86        if (msg->nlmsg_type == RTM_GETNEIGH) {
87                debugf(NHRP_DEBUG_KERNEL, "Netlink: who-has %s dev %s",
88                        sockunion2str(&addr, buf, sizeof buf),
89                        ifp->name);
90
91                if (c->cur.type >= NHRP_CACHE_CACHED) {
92                        nhrp_cache_set_used(c, 1);
93                        netlink_update_binding(ifp, &addr, &c->cur.peer->vc->remote.nbma);
94                }
95        } else {
96                debugf(NHRP_DEBUG_KERNEL, "Netlink: update %s dev %s nud %x",
97                        sockunion2str(&addr, buf, sizeof buf),
98                        ifp->name, ndm->ndm_state);
99
100                state = (msg->nlmsg_type == RTM_NEWNEIGH) ? ndm->ndm_state : NUD_FAILED;
101                nhrp_cache_set_used(c, state == NUD_REACHABLE);
102        }
103}
104
105static int netlink_route_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        zbuf_init(&zb, buf, sizeof(buf), 0);
113        while (zbuf_recv(&zb, fd) > 0) {
114                while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) {
115                        debugf(NHRP_DEBUG_KERNEL, "Netlink: Received msg_type %u, msg_flags %u",
116                                n->nlmsg_type, n->nlmsg_flags);
117                        switch (n->nlmsg_type) {
118                        case RTM_GETNEIGH:
119                        case RTM_NEWNEIGH:
120                        case RTM_DELNEIGH:
121                                netlink_neigh_msg(n, &payload);
122                                break;
123                        }
124                }
125        }
126
127        thread_add_read(master, netlink_route_recv, 0, fd);
128
129        return 0;
130}
131
132static void netlink_log_register(int fd, int group)
133{
134        struct nlmsghdr *n;
135        struct nfgenmsg *nf;
136        struct nfulnl_msg_config_cmd cmd;
137        struct zbuf *zb = zbuf_alloc(512);
138
139        n = znl_nlmsg_push(zb, (NFNL_SUBSYS_ULOG<<8) | NFULNL_MSG_CONFIG, NLM_F_REQUEST | NLM_F_ACK);
140        nf = znl_push(zb, sizeof(*nf));
141        *nf = (struct nfgenmsg) {
142                .nfgen_family = AF_UNSPEC,
143                .version = NFNETLINK_V0,
144                .res_id = htons(group),
145        };
146        cmd.command = NFULNL_CFG_CMD_BIND;
147        znl_rta_push(zb, NFULA_CFG_CMD, &cmd, sizeof(cmd));
148        znl_nlmsg_complete(zb, n);
149
150        zbuf_send(zb, fd);
151        zbuf_free(zb);
152}
153
154static void netlink_log_indication(struct nlmsghdr *msg, struct zbuf *zb)
155{
156        struct nfgenmsg *nf;
157        struct rtattr *rta;
158        struct zbuf rtapl, pktpl;
159        struct interface *ifp;
160        struct nfulnl_msg_packet_hdr *pkthdr = NULL;
161        uint32_t *in_ndx = NULL;
162
163        nf = znl_pull(zb, sizeof(*nf));
164        if (!nf) return;
165
166        memset(&pktpl, 0, sizeof(pktpl));
167        while ((rta = znl_rta_pull(zb, &rtapl)) != NULL) {
168                switch (rta->rta_type) {
169                case NFULA_PACKET_HDR:
170                        pkthdr = znl_pull(&rtapl, sizeof(*pkthdr));
171                        break;
172                case NFULA_IFINDEX_INDEV:
173                        in_ndx = znl_pull(&rtapl, sizeof(*in_ndx));
174                        break;
175                case NFULA_PAYLOAD:
176                        pktpl = rtapl;
177                        break;
178                /* NFULA_HWHDR exists and is supposed to contain source
179                 * hardware address. However, for ip_gre it seems to be
180                 * the nexthop destination address if the packet matches
181                 * route. */
182                }
183        }
184
185        if (!pkthdr || !in_ndx || !zbuf_used(&pktpl))
186                return;
187
188        ifp = if_lookup_by_index(htonl(*in_ndx));
189        if (!ifp)
190                return;
191
192        nhrp_peer_send_indication(ifp, htons(pkthdr->hw_protocol), &pktpl);
193}
194
195static int netlink_log_recv(struct thread *t)
196{
197        uint8_t buf[ZNL_BUFFER_SIZE];
198        int fd = THREAD_FD(t);
199        struct zbuf payload, zb;
200        struct nlmsghdr *n;
201
202        netlink_log_thread = NULL;
203
204        zbuf_init(&zb, buf, sizeof(buf), 0);
205        while (zbuf_recv(&zb, fd) > 0) {
206                while ((n = znl_nlmsg_pull(&zb, &payload)) != 0) {
207                        debugf(NHRP_DEBUG_KERNEL, "Netlink-log: Received msg_type %u, msg_flags %u",
208                                n->nlmsg_type, n->nlmsg_flags);
209                        switch (n->nlmsg_type) {
210                        case (NFNL_SUBSYS_ULOG<<8) | NFULNL_MSG_PACKET:
211                                netlink_log_indication(n, &payload);
212                                break;
213                        }
214                }
215        }
216
217        THREAD_READ_ON(master, netlink_log_thread, netlink_log_recv, 0, netlink_log_fd);
218
219        return 0;
220}
221
222void netlink_set_nflog_group(int nlgroup)
223{
224        if (netlink_log_fd >= 0) {
225                THREAD_OFF(netlink_log_thread);
226                close(netlink_log_fd);
227                netlink_log_fd = -1;
228        }
229        netlink_nflog_group = nlgroup;
230        if (nlgroup) {
231                netlink_log_fd = znl_open(NETLINK_NETFILTER,  0);
232                netlink_log_register(netlink_log_fd, nlgroup);
233                THREAD_READ_ON(master, netlink_log_thread, netlink_log_recv, 0, netlink_log_fd);
234        }
235}
236
237int netlink_init(void)
238{
239        netlink_req_fd = znl_open(NETLINK_ROUTE, 0);
240        netlink_listen_fd = znl_open(NETLINK_ROUTE, RTMGRP_NEIGH);
241        thread_add_read(master, netlink_route_recv, 0, netlink_listen_fd);
242
243        return 0;
244}
245
246int netlink_configure_arp(unsigned int ifindex, int pf)
247{
248        struct nlmsghdr *n;
249        struct ndtmsg *ndtm;
250        struct rtattr *rta;
251        struct zbuf *zb = zbuf_alloc(512);
252        int r;
253
254        n = znl_nlmsg_push(zb, RTM_SETNEIGHTBL, NLM_F_REQUEST | NLM_F_REPLACE);
255        ndtm = znl_push(zb, sizeof(*ndtm));
256        *ndtm = (struct ndtmsg) {
257                .ndtm_family = pf,
258        };
259
260        znl_rta_push(zb, NDTA_NAME, pf == AF_INET ? "arp_cache" : "ndisc_cache", 10);
261
262        rta = znl_rta_nested_push(zb, NDTA_PARMS);
263        znl_rta_push_u32(zb, NDTPA_IFINDEX, ifindex);
264        znl_rta_push_u32(zb, NDTPA_APP_PROBES, 1);
265        znl_rta_push_u32(zb, NDTPA_MCAST_PROBES, 0);
266        znl_rta_push_u32(zb, NDTPA_UCAST_PROBES, 0);
267        znl_rta_nested_complete(zb, rta);
268
269        znl_nlmsg_complete(zb, n);
270        r = zbuf_send(zb, netlink_req_fd);
271        zbuf_recv(zb, netlink_req_fd);
272        zbuf_free(zb);
273
274        return r;
275}
Note: See TracBrowser for help on using the repository browser.