1 /* NHRP netlink/neighbor table arpd code
2 * Copyright (c) 2014-2016 Timo Teräs
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.
16 #include <netinet/if_ether.h>
17 #include <linux/netlink.h>
18 #include <linux/neighbour.h>
19 #include <linux/netfilter/nfnetlink_log.h>
28 int netlink_nflog_group
;
29 static int netlink_log_fd
= -1;
30 static struct thread
*netlink_log_thread
;
32 void netlink_update_binding(struct interface
*ifp
, union sockunion
*proto
,
33 union sockunion
*nbma
)
35 nhrp_send_zebra_nbr(proto
, nbma
, ifp
);
38 static void netlink_log_register(int fd
, int group
)
42 struct nfulnl_msg_config_cmd cmd
;
43 struct zbuf
*zb
= zbuf_alloc(512);
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
),
53 cmd
.command
= NFULNL_CFG_CMD_BIND
;
54 znl_rta_push(zb
, NFULA_CFG_CMD
, &cmd
, sizeof(cmd
));
55 znl_nlmsg_complete(zb
, n
);
61 static void netlink_log_indication(struct nlmsghdr
*msg
, struct zbuf
*zb
)
65 struct zbuf rtapl
, pktpl
;
66 struct interface
*ifp
;
67 struct nfulnl_msg_packet_hdr
*pkthdr
= NULL
;
68 uint32_t *in_ndx
= NULL
;
70 nf
= znl_pull(zb
, sizeof(*nf
));
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
));
80 case NFULA_IFINDEX_INDEV
:
81 in_ndx
= znl_pull(&rtapl
, sizeof(*in_ndx
));
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
93 if (!pkthdr
|| !in_ndx
|| !zbuf_used(&pktpl
))
96 ifp
= if_lookup_by_index(htonl(*in_ndx
), VRF_DEFAULT
);
100 nhrp_peer_send_indication(ifp
, htons(pkthdr
->hw_protocol
), &pktpl
);
103 static int netlink_log_recv(struct thread
*t
)
105 uint8_t buf
[ZNL_BUFFER_SIZE
];
106 int fd
= THREAD_FD(t
);
107 struct zbuf payload
, zb
;
110 netlink_log_thread
= NULL
;
112 zbuf_init(&zb
, buf
, sizeof(buf
), 0);
113 while (zbuf_recv(&zb
, fd
) > 0) {
114 while ((n
= znl_nlmsg_pull(&zb
, &payload
)) != NULL
) {
115 debugf(NHRP_DEBUG_KERNEL
,
116 "Netlink-log: Received msg_type %u, msg_flags %u",
117 n
->nlmsg_type
, n
->nlmsg_flags
);
118 switch (n
->nlmsg_type
) {
119 case (NFNL_SUBSYS_ULOG
<< 8) | NFULNL_MSG_PACKET
:
120 netlink_log_indication(n
, &payload
);
126 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
127 &netlink_log_thread
);
132 void netlink_set_nflog_group(int nlgroup
)
134 if (netlink_log_fd
>= 0) {
135 thread_cancel(&netlink_log_thread
);
136 close(netlink_log_fd
);
139 netlink_nflog_group
= nlgroup
;
141 netlink_log_fd
= znl_open(NETLINK_NETFILTER
, 0);
142 if (netlink_log_fd
< 0)
145 netlink_log_register(netlink_log_fd
, nlgroup
);
146 thread_add_read(master
, netlink_log_recv
, 0, netlink_log_fd
,
147 &netlink_log_thread
);
151 void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS
)
153 union sockunion addr
= {}, lladdr
= {};
154 struct interface
*ifp
;
155 int state
, ndm_state
;
156 struct nhrp_cache
*c
;
157 struct zapi_neigh_ip api
= {};
159 zclient_neigh_ip_decode(zclient
->ibuf
, &api
);
160 if (api
.ip_in
.ipa_type
== AF_UNSPEC
)
162 sockunion_family(&addr
) = api
.ip_in
.ipa_type
;
163 memcpy((uint8_t *)sockunion_get_addr(&addr
), &api
.ip_in
.ip
.addr
,
164 family2addrsize(api
.ip_in
.ipa_type
));
166 sockunion_family(&lladdr
) = api
.ip_out
.ipa_type
;
167 if (api
.ip_out
.ipa_type
!= AF_UNSPEC
)
168 memcpy((uint8_t *)sockunion_get_addr(&lladdr
),
170 family2addrsize(api
.ip_out
.ipa_type
));
172 ifp
= if_lookup_by_index(api
.index
, vrf_id
);
173 ndm_state
= api
.ndm_state
;
177 c
= nhrp_cache_get(ifp
, &addr
, 0);
180 debugf(NHRP_DEBUG_KERNEL
,
181 "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u",
182 (cmd
== ZEBRA_NHRP_NEIGH_GET
)
184 : (cmd
== ZEBRA_NHRP_NEIGH_ADDED
) ? "new-neigh"
186 &addr
, ifp
->name
, &lladdr
, ndm_state
, c
->used
, c
->cur
.type
);
187 if (cmd
== ZEBRA_NHRP_NEIGH_GET
) {
188 if (c
->cur
.type
>= NHRP_CACHE_CACHED
) {
189 nhrp_cache_set_used(c
, 1);
190 debugf(NHRP_DEBUG_KERNEL
,
191 "Netlink: update binding for %pSU dev %s from c %pSU peer.vc.nbma %pSU to lladdr %pSU",
192 &addr
, ifp
->name
, &c
->cur
.remote_nbma_natoa
,
193 &c
->cur
.peer
->vc
->remote
.nbma
, &lladdr
);
194 /* In case of shortcuts, nbma is given by lladdr, not
197 netlink_update_binding(ifp
, &addr
, &lladdr
);
200 state
= (cmd
== ZEBRA_NHRP_NEIGH_ADDED
) ? ndm_state
201 : ZEBRA_NEIGH_STATE_FAILED
;
202 nhrp_cache_set_used(c
, state
== ZEBRA_NEIGH_STATE_REACHABLE
);