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