]> git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_neigh.c
build, vtysh: extract vtysh commands from .xref
[mirror_frr.git] / zebra / zebra_neigh.c
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
44 DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_INFO, "Zebra neigh table");
45 DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_ENT, "Zebra neigh entry");
46
47 static 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 }
74 RB_GENERATE(zebra_neigh_rb_head, zebra_neigh_ent, rb_node, zebra_neigh_rb_cmp);
75
76 static 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
86 static struct zebra_neigh_ent *
87 zebra_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
117 static 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
126 static 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 */
152 void 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 */
167 void 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
191 void 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 */
207 static 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
217 void 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
243 static 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
257 void 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
267 void 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
273 void zebra_neigh_terminate(void)
274 {
275 struct zebra_neigh_ent *n, *next;
276
277 if (!zrouter.neigh_info)
278 return;
279
280 RB_FOREACH_SAFE (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree,
281 next)
282 zebra_neigh_free(n);
283 XFREE(MTYPE_ZNEIGH_INFO, zneigh_info);
284 }