]>
git.proxmox.com Git - mirror_frr.git/blob - lib/if_rmap.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* route-map for interface.
3 * Copyright (C) 1999 Kunihiro Ishiguro
4 * Copyright (C) 2023 LabN Consulting, L.L.C.
14 #include "northbound_cli.h"
16 #include "lib/if_rmap_clippy.c"
18 DEFINE_MTYPE_STATIC(LIB
, IF_RMAP_CTX
, "Interface route map container");
19 DEFINE_MTYPE_STATIC(LIB
, IF_RMAP_CTX_NAME
,
20 "Interface route map container name");
21 DEFINE_MTYPE_STATIC(LIB
, IF_RMAP
, "Interface route map");
22 DEFINE_MTYPE_STATIC(LIB
, IF_RMAP_NAME
, "I.f. route map name");
24 static struct if_rmap
*if_rmap_new(void)
28 new = XCALLOC(MTYPE_IF_RMAP
, sizeof(struct if_rmap
));
33 static void if_rmap_free(struct if_rmap
*if_rmap
)
35 char *no_const_ifname
= (char *)if_rmap
->ifname
;
37 XFREE(MTYPE_IF_RMAP_NAME
, no_const_ifname
);
39 XFREE(MTYPE_IF_RMAP_NAME
, if_rmap
->routemap
[IF_RMAP_IN
]);
40 XFREE(MTYPE_IF_RMAP_NAME
, if_rmap
->routemap
[IF_RMAP_OUT
]);
42 XFREE(MTYPE_IF_RMAP
, if_rmap
);
45 struct if_rmap
*if_rmap_lookup(struct if_rmap_ctx
*ctx
, const char *ifname
)
47 struct if_rmap key
= {.ifname
= ifname
};
48 struct if_rmap
*if_rmap
;
50 if_rmap
= hash_lookup(ctx
->ifrmaphash
, &key
);
55 void if_rmap_hook_add(struct if_rmap_ctx
*ctx
,
56 void (*func
)(struct if_rmap_ctx
*ctx
, struct if_rmap
*))
58 ctx
->if_rmap_add_hook
= func
;
61 void if_rmap_hook_delete(struct if_rmap_ctx
*ctx
,
62 void (*func
)(struct if_rmap_ctx
*ctx
,
65 ctx
->if_rmap_delete_hook
= func
;
68 static void *if_rmap_hash_alloc(void *arg
)
70 struct if_rmap
*ifarg
= (struct if_rmap
*)arg
;
71 struct if_rmap
*if_rmap
;
73 if_rmap
= if_rmap_new();
74 if_rmap
->ifname
= XSTRDUP(MTYPE_IF_RMAP_NAME
, ifarg
->ifname
);
79 static struct if_rmap
*if_rmap_get(struct if_rmap_ctx
*ctx
, const char *ifname
)
81 struct if_rmap key
= {.ifname
= ifname
};
84 ret
= hash_get(ctx
->ifrmaphash
, &key
, if_rmap_hash_alloc
);
89 static unsigned int if_rmap_hash_make(const void *data
)
91 const struct if_rmap
*if_rmap
= data
;
93 return string_hash_make(if_rmap
->ifname
);
96 static bool if_rmap_hash_cmp(const void *arg1
, const void *arg2
)
98 const struct if_rmap
*if_rmap1
= arg1
;
99 const struct if_rmap
*if_rmap2
= arg2
;
101 return strcmp(if_rmap1
->ifname
, if_rmap2
->ifname
) == 0;
104 static void if_rmap_set(struct if_rmap_ctx
*ctx
, const char *ifname
,
105 enum if_rmap_type type
, const char *routemap_name
)
107 struct if_rmap
*if_rmap
= if_rmap_get(ctx
, ifname
);
109 assert(type
== IF_RMAP_IN
|| type
== IF_RMAP_OUT
);
110 XFREE(MTYPE_IF_RMAP_NAME
, if_rmap
->routemap
[type
]);
111 if_rmap
->routemap
[type
] = XSTRDUP(MTYPE_IF_RMAP_NAME
, routemap_name
);
113 if (ctx
->if_rmap_add_hook
)
114 (ctx
->if_rmap_add_hook
)(ctx
, if_rmap
);
117 static void if_rmap_unset(struct if_rmap_ctx
*ctx
, const char *ifname
,
118 enum if_rmap_type type
)
120 struct if_rmap
*if_rmap
= if_rmap_lookup(ctx
, ifname
);
125 assert(type
== IF_RMAP_IN
|| type
== IF_RMAP_OUT
);
126 if (!if_rmap
->routemap
[type
])
129 XFREE(MTYPE_IF_RMAP_NAME
, if_rmap
->routemap
[type
]);
131 if (ctx
->if_rmap_delete_hook
)
132 ctx
->if_rmap_delete_hook(ctx
, if_rmap
);
134 if (if_rmap
->routemap
[IF_RMAP_IN
] == NULL
&&
135 if_rmap
->routemap
[IF_RMAP_OUT
] == NULL
) {
136 hash_release(ctx
->ifrmaphash
, if_rmap
);
137 if_rmap_free(if_rmap
);
141 static int if_route_map_handler(struct vty
*vty
, bool no
, const char *dir
,
142 const char *other_dir
, const char *ifname
,
143 const char *route_map
)
145 enum nb_operation op
= no
? NB_OP_DESTROY
: NB_OP_MODIFY
;
146 const struct lyd_node
*dnode
;
147 char xpath
[XPATH_MAXLEN
];
151 xpath
, sizeof(xpath
),
152 "./if-route-maps/if-route-map[interface='%s']/%s-route-map",
156 * If we are deleting the last policy for this interface,
157 * (i.e., no `in` or `out` policy). delete the interface list
160 dnode
= yang_dnode_get(vty
->candidate_config
->dnode
,
162 if (yang_dnode_existsf(
164 "./if-route-maps/if-route-map[interface='%s']/%s-route-map",
165 ifname
, other_dir
)) {
167 xpath
, sizeof(xpath
),
168 "./if-route-maps/if-route-map[interface='%s']/%s-route-map",
171 /* both dir will be empty so delete the list node */
172 snprintf(xpath
, sizeof(xpath
),
173 "./if-route-maps/if-route-map[interface='%s']",
177 nb_cli_enqueue_change(vty
, xpath
, op
, route_map
);
179 return nb_cli_apply_changes(vty
, NULL
);
182 DEFPY_YANG(if_ipv4_route_map
, if_ipv4_route_map_cmd
,
183 "route-map ROUTE-MAP <in$in|out> IFNAME",
186 "Route map set for input filtering\n"
187 "Route map set for output filtering\n" INTERFACE_STR
)
189 const char *dir
= in
? "in" : "out";
190 const char *other_dir
= in
? "out" : "in";
192 return if_route_map_handler(vty
, false, dir
, other_dir
, ifname
,
196 DEFPY_YANG(no_if_ipv4_route_map
, no_if_ipv4_route_map_cmd
,
197 "no route-map [ROUTE-MAP] <in$in|out> IFNAME",
201 "Route map set for input filtering\n"
202 "Route map set for output filtering\n" INTERFACE_STR
)
204 const char *dir
= in
? "in" : "out";
205 const char *other_dir
= in
? "out" : "in";
207 return if_route_map_handler(vty
, true, dir
, other_dir
, ifname
,
212 * CLI infra requires new handlers for ripngd
214 DEFPY_YANG(if_ipv6_route_map
, if_ipv6_route_map_cmd
,
215 "route-map ROUTE-MAP <in$in|out> IFNAME",
218 "Route map set for input filtering\n"
219 "Route map set for output filtering\n" INTERFACE_STR
)
221 const char *dir
= in
? "in" : "out";
222 const char *other_dir
= in
? "out" : "in";
224 return if_route_map_handler(vty
, false, dir
, other_dir
, ifname
,
228 DEFPY_YANG(no_if_ipv6_route_map
, no_if_ipv6_route_map_cmd
,
229 "no route-map [ROUTE-MAP] <in$in|out> IFNAME",
233 "Route map set for input filtering\n"
234 "Route map set for output filtering\n" INTERFACE_STR
)
236 const char *dir
= in
? "in" : "out";
237 const char *other_dir
= in
? "out" : "in";
239 return if_route_map_handler(vty
, true, dir
, other_dir
, ifname
,
243 void cli_show_if_route_map(struct vty
*vty
, const struct lyd_node
*dnode
,
246 if (yang_dnode_exists(dnode
, "./in-route-map"))
247 vty_out(vty
, " route-map %s in %s\n",
248 yang_dnode_get_string(dnode
, "./in-route-map"),
249 yang_dnode_get_string(dnode
, "./interface"));
250 if (yang_dnode_exists(dnode
, "./out-route-map"))
251 vty_out(vty
, " route-map %s out %s\n",
252 yang_dnode_get_string(dnode
, "./out-route-map"),
253 yang_dnode_get_string(dnode
, "./interface"));
256 void if_rmap_yang_modify_cb(struct if_rmap_ctx
*ctx
,
257 const struct lyd_node
*dnode
,
258 enum if_rmap_type type
, bool del
)
261 const char *mapname
= yang_dnode_get_string(dnode
, NULL
);
262 const char *ifname
= yang_dnode_get_string(dnode
, "../interface");
265 if_rmap_unset(ctx
, ifname
, type
);
267 if_rmap_set(ctx
, ifname
, type
, mapname
);
270 void if_rmap_yang_destroy_cb(struct if_rmap_ctx
*ctx
,
271 const struct lyd_node
*dnode
)
273 const char *ifname
= yang_dnode_get_string(dnode
, "interface");
274 if_rmap_unset(ctx
, ifname
, IF_RMAP_IN
);
275 if_rmap_unset(ctx
, ifname
, IF_RMAP_OUT
);
278 void if_rmap_ctx_delete(struct if_rmap_ctx
*ctx
)
280 hash_clean_and_free(&ctx
->ifrmaphash
, (void (*)(void *))if_rmap_free
);
281 XFREE(MTYPE_IF_RMAP_CTX_NAME
, ctx
->name
);
282 XFREE(MTYPE_IF_RMAP_CTX
, ctx
);
285 /* name is optional: either vrf name, or other */
286 struct if_rmap_ctx
*if_rmap_ctx_create(const char *name
)
288 struct if_rmap_ctx
*ctx
;
290 ctx
= XCALLOC(MTYPE_IF_RMAP_CTX
, sizeof(struct if_rmap_ctx
));
292 ctx
->name
= XSTRDUP(MTYPE_IF_RMAP_CTX_NAME
, name
);
294 hash_create_size(4, if_rmap_hash_make
, if_rmap_hash_cmp
,
295 "Interface Route-Map Hash");
299 void if_rmap_init(int node
)
301 if (node
== RIP_NODE
) {
302 install_element(RIP_NODE
, &if_ipv4_route_map_cmd
);
303 install_element(RIP_NODE
, &no_if_ipv4_route_map_cmd
);
304 } else if (node
== RIPNG_NODE
) {
305 install_element(RIPNG_NODE
, &if_ipv6_route_map_cmd
);
306 install_element(RIPNG_NODE
, &no_if_ipv6_route_map_cmd
);
310 void if_rmap_terminate(void)