]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_neigh.c
*: manual SPDX License ID conversions
[mirror_frr.git] / zebra / zebra_neigh.c
CommitLineData
4cf4fad1
AK
1/*
2 * Zebra neighbor table management
3 *
4 * Copyright (C) 2021 Nvidia
5 * Anuradha Karuppiah
6 *
7 * This file is part of FRR.
8 *
9 * FRR is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2, or (at your option) any
12 * later version.
13 *
14 * FRR is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 */
19
20#include <zebra.h>
21
22#include "command.h"
23#include "hash.h"
24#include "if.h"
25#include "jhash.h"
26#include "linklist.h"
27#include "log.h"
28#include "memory.h"
29#include "prefix.h"
30#include "stream.h"
31#include "table.h"
32
33#include "zebra/zebra_router.h"
34#include "zebra/debug.h"
35#include "zebra/interface.h"
36#include "zebra/rib.h"
37#include "zebra/rt.h"
38#include "zebra/rt_netlink.h"
39#include "zebra/zebra_errors.h"
40#include "zebra/interface.h"
41#include "zebra/zebra_neigh.h"
42#include "zebra/zebra_pbr.h"
43
44DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_INFO, "Zebra neigh table");
45DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_ENT, "Zebra neigh entry");
46
47static int zebra_neigh_rb_cmp(const struct zebra_neigh_ent *n1,
48 const struct zebra_neigh_ent *n2)
49{
50 if (n1->ifindex < n2->ifindex)
51 return -1;
52
53 if (n1->ifindex > n2->ifindex)
54 return 1;
55
56 if (n1->ip.ipa_type < n2->ip.ipa_type)
57 return -1;
58
59 if (n1->ip.ipa_type > n2->ip.ipa_type)
60 return 1;
61
62 if (n1->ip.ipa_type == AF_INET) {
63 if (n1->ip.ipaddr_v4.s_addr < n2->ip.ipaddr_v4.s_addr)
64 return -1;
65
66 if (n1->ip.ipaddr_v4.s_addr > n2->ip.ipaddr_v4.s_addr)
67 return 1;
68
69 return 0;
70 }
71
72 return memcmp(&n1->ip.ipaddr_v6, &n2->ip.ipaddr_v6, IPV6_MAX_BYTELEN);
73}
74RB_GENERATE(zebra_neigh_rb_head, zebra_neigh_ent, rb_node, zebra_neigh_rb_cmp);
75
76static struct zebra_neigh_ent *zebra_neigh_find(ifindex_t ifindex,
77 struct ipaddr *ip)
78{
79 struct zebra_neigh_ent tmp;
80
81 tmp.ifindex = ifindex;
82 memcpy(&tmp.ip, ip, sizeof(*ip));
83 return RB_FIND(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, &tmp);
84}
85
86static struct zebra_neigh_ent *
87zebra_neigh_new(ifindex_t ifindex, struct ipaddr *ip, struct ethaddr *mac)
88{
89 struct zebra_neigh_ent *n;
90
91 n = XCALLOC(MTYPE_ZNEIGH_ENT, sizeof(struct zebra_neigh_ent));
92
93 memcpy(&n->ip, ip, sizeof(*ip));
94 n->ifindex = ifindex;
95 if (mac) {
96 memcpy(&n->mac, mac, sizeof(*mac));
97 n->flags |= ZEBRA_NEIGH_ENT_ACTIVE;
98 }
99
100 /* Add to rb_tree */
101 if (RB_INSERT(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, n)) {
102 XFREE(MTYPE_ZNEIGH_ENT, n);
103 return NULL;
104 }
105
106 /* Initialise the pbr rule list */
107 n->pbr_rule_list = list_new();
108 listset_app_node_mem(n->pbr_rule_list);
109
110 if (IS_ZEBRA_DEBUG_NEIGH)
111 zlog_debug("zebra neigh new if %d %pIA %pEA", n->ifindex,
112 &n->ip, &n->mac);
113
114 return n;
115}
116
117static void zebra_neigh_pbr_rules_update(struct zebra_neigh_ent *n)
118{
119 struct zebra_pbr_rule *rule;
120 struct listnode *node;
121
122 for (ALL_LIST_ELEMENTS_RO(n->pbr_rule_list, node, rule))
123 dplane_pbr_rule_update(rule, rule);
124}
125
126static void zebra_neigh_free(struct zebra_neigh_ent *n)
127{
128 if (listcount(n->pbr_rule_list)) {
129 /* if rules are still using the neigh mark it as inactive and
130 * update the dataplane
131 */
132 if (n->flags & ZEBRA_NEIGH_ENT_ACTIVE) {
133 n->flags &= ~ZEBRA_NEIGH_ENT_ACTIVE;
134 memset(&n->mac, 0, sizeof(n->mac));
135 }
136 zebra_neigh_pbr_rules_update(n);
137 return;
138 }
139 if (IS_ZEBRA_DEBUG_NEIGH)
140 zlog_debug("zebra neigh free if %d %pIA %pEA", n->ifindex,
141 &n->ip, &n->mac);
142
143 /* cleanup resources maintained against the neigh */
144 list_delete(&n->pbr_rule_list);
145
146 RB_REMOVE(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, n);
147
148 XFREE(MTYPE_ZNEIGH_ENT, n);
149}
150
151/* kernel neigh del */
152void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip)
153{
154 struct zebra_neigh_ent *n;
155
156 if (IS_ZEBRA_DEBUG_NEIGH)
157 zlog_debug("zebra neigh del if %s/%d %pIA", ifp->name,
158 ifp->ifindex, ip);
159
160 n = zebra_neigh_find(ifp->ifindex, ip);
161 if (!n)
162 return;
163 zebra_neigh_free(n);
164}
165
166/* kernel neigh add */
167void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip,
168 struct ethaddr *mac)
169{
170 struct zebra_neigh_ent *n;
171
172 if (IS_ZEBRA_DEBUG_NEIGH)
173 zlog_debug("zebra neigh add if %s/%d %pIA %pEA", ifp->name,
174 ifp->ifindex, ip, mac);
175
176 n = zebra_neigh_find(ifp->ifindex, ip);
177 if (n) {
178 if (!memcmp(&n->mac, mac, sizeof(*mac)))
179 return;
180
181 memcpy(&n->mac, mac, sizeof(*mac));
182 n->flags |= ZEBRA_NEIGH_ENT_ACTIVE;
183
184 /* update rules linked to the neigh */
185 zebra_neigh_pbr_rules_update(n);
186 } else {
187 zebra_neigh_new(ifp->ifindex, ip, mac);
188 }
189}
190
191void zebra_neigh_deref(struct zebra_pbr_rule *rule)
192{
193 struct zebra_neigh_ent *n = rule->action.neigh;
194
195 if (IS_ZEBRA_DEBUG_NEIGH)
196 zlog_debug("zebra neigh deref if %d %pIA by pbr rule %u",
197 n->ifindex, &n->ip, rule->rule.seq);
198
199 rule->action.neigh = NULL;
200 /* remove rule from the list and free if it is inactive */
201 list_delete_node(n->pbr_rule_list, &rule->action.neigh_listnode);
202 if (!(n->flags & ZEBRA_NEIGH_ENT_ACTIVE))
203 zebra_neigh_free(n);
204}
205
206/* XXX - this needs to work with evpn's neigh read */
207static void zebra_neigh_read_on_first_ref(void)
208{
209 static bool neigh_read_done;
210
211 if (!neigh_read_done) {
212 neigh_read(zebra_ns_lookup(NS_DEFAULT));
213 neigh_read_done = true;
214 }
215}
216
217void zebra_neigh_ref(int ifindex, struct ipaddr *ip,
218 struct zebra_pbr_rule *rule)
219{
220 struct zebra_neigh_ent *n;
221
222 if (IS_ZEBRA_DEBUG_NEIGH)
223 zlog_debug("zebra neigh ref if %d %pIA by pbr rule %u", ifindex,
224 ip, rule->rule.seq);
225
226 zebra_neigh_read_on_first_ref();
227 n = zebra_neigh_find(ifindex, ip);
228 if (!n)
229 n = zebra_neigh_new(ifindex, ip, NULL);
230
231 /* link the pbr entry to the neigh */
232 if (rule->action.neigh == n)
233 return;
234
235 if (rule->action.neigh)
236 zebra_neigh_deref(rule);
237
238 rule->action.neigh = n;
239 listnode_init(&rule->action.neigh_listnode, rule);
240 listnode_add(n->pbr_rule_list, &rule->action.neigh_listnode);
241}
242
243static void zebra_neigh_show_one(struct vty *vty, struct zebra_neigh_ent *n)
244{
245 char mac_buf[ETHER_ADDR_STRLEN];
246 char ip_buf[INET6_ADDRSTRLEN];
247 struct interface *ifp;
248
249 ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
250 n->ifindex);
251 ipaddr2str(&n->ip, ip_buf, sizeof(ip_buf));
252 prefix_mac2str(&n->mac, mac_buf, sizeof(mac_buf));
253 vty_out(vty, "%-20s %-30s %-18s %u\n", ifp ? ifp->name : "-", ip_buf,
254 mac_buf, listcount(n->pbr_rule_list));
255}
256
257void zebra_neigh_show(struct vty *vty)
258{
259 struct zebra_neigh_ent *n;
260
261 vty_out(vty, "%-20s %-30s %-18s %s\n", "Interface", "Neighbor", "MAC",
262 "#Rules");
263 RB_FOREACH (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree)
264 zebra_neigh_show_one(vty, n);
265}
266
267void zebra_neigh_init(void)
268{
269 zneigh_info = XCALLOC(MTYPE_ZNEIGH_INFO, sizeof(*zrouter.neigh_info));
270 RB_INIT(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree);
271}
272
273void zebra_neigh_terminate(void)
274{
11c9ab32
CH
275 struct zebra_neigh_ent *n, *next;
276
4cf4fad1
AK
277 if (!zrouter.neigh_info)
278 return;
279
11c9ab32
CH
280 RB_FOREACH_SAFE (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree,
281 next)
282 zebra_neigh_free(n);
4cf4fad1
AK
283 XFREE(MTYPE_ZNEIGH_INFO, zneigh_info);
284}