]>
git.proxmox.com Git - mirror_frr.git/blob - zebra/zebra_neigh.c
2 * Zebra neighbor table management
4 * Copyright (C) 2021 Nvidia
7 * This file is part of FRR.
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
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.
33 #include "zebra/zebra_router.h"
34 #include "zebra/debug.h"
35 #include "zebra/interface.h"
36 #include "zebra/rib.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"
44 DEFINE_MTYPE_STATIC(ZEBRA
, ZNEIGH_INFO
, "Zebra neigh table");
45 DEFINE_MTYPE_STATIC(ZEBRA
, ZNEIGH_ENT
, "Zebra neigh entry");
47 static int zebra_neigh_rb_cmp(const struct zebra_neigh_ent
*n1
,
48 const struct zebra_neigh_ent
*n2
)
50 if (n1
->ifindex
< n2
->ifindex
)
53 if (n1
->ifindex
> n2
->ifindex
)
56 if (n1
->ip
.ipa_type
< n2
->ip
.ipa_type
)
59 if (n1
->ip
.ipa_type
> n2
->ip
.ipa_type
)
62 if (n1
->ip
.ipa_type
== AF_INET
) {
63 if (n1
->ip
.ipaddr_v4
.s_addr
< n2
->ip
.ipaddr_v4
.s_addr
)
66 if (n1
->ip
.ipaddr_v4
.s_addr
> n2
->ip
.ipaddr_v4
.s_addr
)
72 return memcmp(&n1
->ip
.ipaddr_v6
, &n2
->ip
.ipaddr_v6
, IPV6_MAX_BYTELEN
);
74 RB_GENERATE(zebra_neigh_rb_head
, zebra_neigh_ent
, rb_node
, zebra_neigh_rb_cmp
);
76 static struct zebra_neigh_ent
*zebra_neigh_find(ifindex_t ifindex
,
79 struct zebra_neigh_ent tmp
;
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
);
86 static struct zebra_neigh_ent
*
87 zebra_neigh_new(ifindex_t ifindex
, struct ipaddr
*ip
, struct ethaddr
*mac
)
89 struct zebra_neigh_ent
*n
;
91 n
= XCALLOC(MTYPE_ZNEIGH_ENT
, sizeof(struct zebra_neigh_ent
));
93 memcpy(&n
->ip
, ip
, sizeof(*ip
));
96 memcpy(&n
->mac
, mac
, sizeof(*mac
));
97 n
->flags
|= ZEBRA_NEIGH_ENT_ACTIVE
;
101 if (RB_INSERT(zebra_neigh_rb_head
, &zneigh_info
->neigh_rb_tree
, n
)) {
102 XFREE(MTYPE_ZNEIGH_ENT
, n
);
106 /* Initialise the pbr rule list */
107 n
->pbr_rule_list
= list_new();
108 listset_app_node_mem(n
->pbr_rule_list
);
110 if (IS_ZEBRA_DEBUG_NEIGH
)
111 zlog_debug("zebra neigh new if %d %pIA %pEA", n
->ifindex
,
117 static void zebra_neigh_pbr_rules_update(struct zebra_neigh_ent
*n
)
119 struct zebra_pbr_rule
*rule
;
120 struct listnode
*node
;
122 for (ALL_LIST_ELEMENTS_RO(n
->pbr_rule_list
, node
, rule
))
123 dplane_pbr_rule_update(rule
, rule
);
126 static void zebra_neigh_free(struct zebra_neigh_ent
*n
)
128 if (listcount(n
->pbr_rule_list
)) {
129 /* if rules are still using the neigh mark it as inactive and
130 * update the dataplane
132 if (n
->flags
& ZEBRA_NEIGH_ENT_ACTIVE
) {
133 n
->flags
&= ~ZEBRA_NEIGH_ENT_ACTIVE
;
134 memset(&n
->mac
, 0, sizeof(n
->mac
));
136 zebra_neigh_pbr_rules_update(n
);
139 if (IS_ZEBRA_DEBUG_NEIGH
)
140 zlog_debug("zebra neigh free if %d %pIA %pEA", n
->ifindex
,
143 /* cleanup resources maintained against the neigh */
144 list_delete(&n
->pbr_rule_list
);
146 RB_REMOVE(zebra_neigh_rb_head
, &zneigh_info
->neigh_rb_tree
, n
);
148 XFREE(MTYPE_ZNEIGH_ENT
, n
);
151 /* kernel neigh del */
152 void zebra_neigh_del(struct interface
*ifp
, struct ipaddr
*ip
)
154 struct zebra_neigh_ent
*n
;
156 if (IS_ZEBRA_DEBUG_NEIGH
)
157 zlog_debug("zebra neigh del if %s/%d %pIA", ifp
->name
,
160 n
= zebra_neigh_find(ifp
->ifindex
, ip
);
166 /* kernel neigh add */
167 void zebra_neigh_add(struct interface
*ifp
, struct ipaddr
*ip
,
170 struct zebra_neigh_ent
*n
;
172 if (IS_ZEBRA_DEBUG_NEIGH
)
173 zlog_debug("zebra neigh add if %s/%d %pIA %pEA", ifp
->name
,
174 ifp
->ifindex
, ip
, mac
);
176 n
= zebra_neigh_find(ifp
->ifindex
, ip
);
178 if (!memcmp(&n
->mac
, mac
, sizeof(*mac
)))
181 memcpy(&n
->mac
, mac
, sizeof(*mac
));
182 n
->flags
|= ZEBRA_NEIGH_ENT_ACTIVE
;
184 /* update rules linked to the neigh */
185 zebra_neigh_pbr_rules_update(n
);
187 zebra_neigh_new(ifp
->ifindex
, ip
, mac
);
191 void zebra_neigh_deref(struct zebra_pbr_rule
*rule
)
193 struct zebra_neigh_ent
*n
= rule
->action
.neigh
;
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
);
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
))
206 /* XXX - this needs to work with evpn's neigh read */
207 static void zebra_neigh_read_on_first_ref(void)
209 static bool neigh_read_done
;
211 if (!neigh_read_done
) {
212 neigh_read(zebra_ns_lookup(NS_DEFAULT
));
213 neigh_read_done
= true;
217 void zebra_neigh_ref(int ifindex
, struct ipaddr
*ip
,
218 struct zebra_pbr_rule
*rule
)
220 struct zebra_neigh_ent
*n
;
222 if (IS_ZEBRA_DEBUG_NEIGH
)
223 zlog_debug("zebra neigh ref if %d %pIA by pbr rule %u", ifindex
,
226 zebra_neigh_read_on_first_ref();
227 n
= zebra_neigh_find(ifindex
, ip
);
229 n
= zebra_neigh_new(ifindex
, ip
, NULL
);
231 /* link the pbr entry to the neigh */
232 if (rule
->action
.neigh
== n
)
235 if (rule
->action
.neigh
)
236 zebra_neigh_deref(rule
);
238 rule
->action
.neigh
= n
;
239 listnode_init(&rule
->action
.neigh_listnode
, rule
);
240 listnode_add(n
->pbr_rule_list
, &rule
->action
.neigh_listnode
);
243 static void zebra_neigh_show_one(struct vty
*vty
, struct zebra_neigh_ent
*n
)
245 char mac_buf
[ETHER_ADDR_STRLEN
];
246 char ip_buf
[INET6_ADDRSTRLEN
];
247 struct interface
*ifp
;
249 ifp
= if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT
),
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
));
257 void zebra_neigh_show(struct vty
*vty
)
259 struct zebra_neigh_ent
*n
;
261 vty_out(vty
, "%-20s %-30s %-18s %s\n", "Interface", "Neighbor", "MAC",
263 RB_FOREACH (n
, zebra_neigh_rb_head
, &zneigh_info
->neigh_rb_tree
)
264 zebra_neigh_show_one(vty
, n
);
267 void zebra_neigh_init(void)
269 zneigh_info
= XCALLOC(MTYPE_ZNEIGH_INFO
, sizeof(*zrouter
.neigh_info
));
270 RB_INIT(zebra_neigh_rb_head
, &zneigh_info
->neigh_rb_tree
);
273 void zebra_neigh_terminate(void)
275 struct zebra_neigh_ent
*n
, *next
;
277 if (!zrouter
.neigh_info
)
280 RB_FOREACH_SAFE (n
, zebra_neigh_rb_head
, &zneigh_info
->neigh_rb_tree
,
283 XFREE(MTYPE_ZNEIGH_INFO
, zneigh_info
);