Line data Source code
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 3 : DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_INFO, "Zebra neigh table");
45 3 : DEFINE_MTYPE_STATIC(ZEBRA, ZNEIGH_ENT, "Zebra neigh entry");
46 :
47 0 : static int zebra_neigh_rb_cmp(const struct zebra_neigh_ent *n1,
48 : const struct zebra_neigh_ent *n2)
49 : {
50 0 : if (n1->ifindex < n2->ifindex)
51 : return -1;
52 :
53 0 : if (n1->ifindex > n2->ifindex)
54 : return 1;
55 :
56 0 : if (n1->ip.ipa_type < n2->ip.ipa_type)
57 : return -1;
58 :
59 0 : if (n1->ip.ipa_type > n2->ip.ipa_type)
60 : return 1;
61 :
62 0 : if (n1->ip.ipa_type == AF_INET) {
63 0 : if (n1->ip.ipaddr_v4.s_addr < n2->ip.ipaddr_v4.s_addr)
64 : return -1;
65 :
66 0 : if (n1->ip.ipaddr_v4.s_addr > n2->ip.ipaddr_v4.s_addr)
67 : return 1;
68 :
69 0 : return 0;
70 : }
71 :
72 0 : return memcmp(&n1->ip.ipaddr_v6, &n2->ip.ipaddr_v6, IPV6_MAX_BYTELEN);
73 : }
74 0 : RB_GENERATE(zebra_neigh_rb_head, zebra_neigh_ent, rb_node, zebra_neigh_rb_cmp);
75 :
76 0 : static struct zebra_neigh_ent *zebra_neigh_find(ifindex_t ifindex,
77 : struct ipaddr *ip)
78 : {
79 0 : struct zebra_neigh_ent tmp;
80 :
81 0 : tmp.ifindex = ifindex;
82 0 : memcpy(&tmp.ip, ip, sizeof(*ip));
83 0 : return RB_FIND(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, &tmp);
84 : }
85 :
86 : static struct zebra_neigh_ent *
87 0 : zebra_neigh_new(ifindex_t ifindex, struct ipaddr *ip, struct ethaddr *mac)
88 : {
89 0 : struct zebra_neigh_ent *n;
90 :
91 0 : n = XCALLOC(MTYPE_ZNEIGH_ENT, sizeof(struct zebra_neigh_ent));
92 :
93 0 : memcpy(&n->ip, ip, sizeof(*ip));
94 0 : n->ifindex = ifindex;
95 0 : if (mac) {
96 0 : memcpy(&n->mac, mac, sizeof(*mac));
97 0 : n->flags |= ZEBRA_NEIGH_ENT_ACTIVE;
98 : }
99 :
100 : /* Add to rb_tree */
101 0 : if (RB_INSERT(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, n)) {
102 0 : XFREE(MTYPE_ZNEIGH_ENT, n);
103 0 : return NULL;
104 : }
105 :
106 : /* Initialise the pbr rule list */
107 0 : n->pbr_rule_list = list_new();
108 0 : listset_app_node_mem(n->pbr_rule_list);
109 :
110 0 : if (IS_ZEBRA_DEBUG_NEIGH)
111 0 : zlog_debug("zebra neigh new if %d %pIA %pEA", n->ifindex,
112 : &n->ip, &n->mac);
113 :
114 : return n;
115 : }
116 :
117 0 : static void zebra_neigh_pbr_rules_update(struct zebra_neigh_ent *n)
118 : {
119 0 : struct zebra_pbr_rule *rule;
120 0 : struct listnode *node;
121 :
122 0 : for (ALL_LIST_ELEMENTS_RO(n->pbr_rule_list, node, rule))
123 0 : dplane_pbr_rule_update(rule, rule);
124 0 : }
125 :
126 0 : static void zebra_neigh_free(struct zebra_neigh_ent *n)
127 : {
128 0 : 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 0 : if (n->flags & ZEBRA_NEIGH_ENT_ACTIVE) {
133 0 : n->flags &= ~ZEBRA_NEIGH_ENT_ACTIVE;
134 0 : memset(&n->mac, 0, sizeof(n->mac));
135 : }
136 0 : zebra_neigh_pbr_rules_update(n);
137 0 : return;
138 : }
139 0 : if (IS_ZEBRA_DEBUG_NEIGH)
140 0 : 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 0 : list_delete(&n->pbr_rule_list);
145 :
146 0 : RB_REMOVE(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree, n);
147 :
148 0 : XFREE(MTYPE_ZNEIGH_ENT, n);
149 : }
150 :
151 : /* kernel neigh del */
152 0 : void zebra_neigh_del(struct interface *ifp, struct ipaddr *ip)
153 : {
154 0 : struct zebra_neigh_ent *n;
155 :
156 0 : if (IS_ZEBRA_DEBUG_NEIGH)
157 0 : zlog_debug("zebra neigh del if %s/%d %pIA", ifp->name,
158 : ifp->ifindex, ip);
159 :
160 0 : n = zebra_neigh_find(ifp->ifindex, ip);
161 0 : if (!n)
162 : return;
163 0 : zebra_neigh_free(n);
164 : }
165 :
166 : /* kernel neigh add */
167 0 : void zebra_neigh_add(struct interface *ifp, struct ipaddr *ip,
168 : struct ethaddr *mac)
169 : {
170 0 : struct zebra_neigh_ent *n;
171 :
172 0 : if (IS_ZEBRA_DEBUG_NEIGH)
173 0 : zlog_debug("zebra neigh add if %s/%d %pIA %pEA", ifp->name,
174 : ifp->ifindex, ip, mac);
175 :
176 0 : n = zebra_neigh_find(ifp->ifindex, ip);
177 0 : if (n) {
178 0 : if (!memcmp(&n->mac, mac, sizeof(*mac)))
179 : return;
180 :
181 0 : memcpy(&n->mac, mac, sizeof(*mac));
182 0 : n->flags |= ZEBRA_NEIGH_ENT_ACTIVE;
183 :
184 : /* update rules linked to the neigh */
185 0 : zebra_neigh_pbr_rules_update(n);
186 : } else {
187 0 : zebra_neigh_new(ifp->ifindex, ip, mac);
188 : }
189 : }
190 :
191 0 : void zebra_neigh_deref(struct zebra_pbr_rule *rule)
192 : {
193 0 : struct zebra_neigh_ent *n = rule->action.neigh;
194 :
195 0 : if (IS_ZEBRA_DEBUG_NEIGH)
196 0 : zlog_debug("zebra neigh deref if %d %pIA by pbr rule %u",
197 : n->ifindex, &n->ip, rule->rule.seq);
198 :
199 0 : rule->action.neigh = NULL;
200 : /* remove rule from the list and free if it is inactive */
201 0 : list_delete_node(n->pbr_rule_list, &rule->action.neigh_listnode);
202 0 : if (!(n->flags & ZEBRA_NEIGH_ENT_ACTIVE))
203 0 : zebra_neigh_free(n);
204 0 : }
205 :
206 : /* XXX - this needs to work with evpn's neigh read */
207 0 : static void zebra_neigh_read_on_first_ref(void)
208 : {
209 0 : static bool neigh_read_done;
210 :
211 0 : if (!neigh_read_done) {
212 0 : neigh_read(zebra_ns_lookup(NS_DEFAULT));
213 0 : neigh_read_done = true;
214 : }
215 0 : }
216 :
217 0 : void zebra_neigh_ref(int ifindex, struct ipaddr *ip,
218 : struct zebra_pbr_rule *rule)
219 : {
220 0 : struct zebra_neigh_ent *n;
221 :
222 0 : if (IS_ZEBRA_DEBUG_NEIGH)
223 0 : zlog_debug("zebra neigh ref if %d %pIA by pbr rule %u", ifindex,
224 : ip, rule->rule.seq);
225 :
226 0 : zebra_neigh_read_on_first_ref();
227 0 : n = zebra_neigh_find(ifindex, ip);
228 0 : if (!n)
229 0 : n = zebra_neigh_new(ifindex, ip, NULL);
230 :
231 : /* link the pbr entry to the neigh */
232 0 : if (rule->action.neigh == n)
233 : return;
234 :
235 0 : if (rule->action.neigh)
236 0 : zebra_neigh_deref(rule);
237 :
238 0 : rule->action.neigh = n;
239 0 : listnode_init(&rule->action.neigh_listnode, rule);
240 0 : listnode_add(n->pbr_rule_list, &rule->action.neigh_listnode);
241 : }
242 :
243 0 : static void zebra_neigh_show_one(struct vty *vty, struct zebra_neigh_ent *n)
244 : {
245 0 : char mac_buf[ETHER_ADDR_STRLEN];
246 0 : char ip_buf[INET6_ADDRSTRLEN];
247 0 : struct interface *ifp;
248 :
249 0 : ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
250 0 : n->ifindex);
251 0 : ipaddr2str(&n->ip, ip_buf, sizeof(ip_buf));
252 0 : prefix_mac2str(&n->mac, mac_buf, sizeof(mac_buf));
253 0 : vty_out(vty, "%-20s %-30s %-18s %u\n", ifp ? ifp->name : "-", ip_buf,
254 0 : mac_buf, listcount(n->pbr_rule_list));
255 0 : }
256 :
257 0 : void zebra_neigh_show(struct vty *vty)
258 : {
259 0 : struct zebra_neigh_ent *n;
260 :
261 0 : vty_out(vty, "%-20s %-30s %-18s %s\n", "Interface", "Neighbor", "MAC",
262 : "#Rules");
263 0 : RB_FOREACH (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree)
264 0 : zebra_neigh_show_one(vty, n);
265 0 : }
266 :
267 1 : void zebra_neigh_init(void)
268 : {
269 1 : zneigh_info = XCALLOC(MTYPE_ZNEIGH_INFO, sizeof(*zrouter.neigh_info));
270 1 : RB_INIT(zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree);
271 1 : }
272 :
273 1 : void zebra_neigh_terminate(void)
274 : {
275 1 : struct zebra_neigh_ent *n, *next;
276 :
277 1 : if (!zrouter.neigh_info)
278 : return;
279 :
280 2 : RB_FOREACH_SAFE (n, zebra_neigh_rb_head, &zneigh_info->neigh_rb_tree,
281 : next)
282 0 : zebra_neigh_free(n);
283 1 : XFREE(MTYPE_ZNEIGH_INFO, zneigh_info);
284 : }
|