mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
Merge pull request #18626 from donaldsharp/RA_me
Some checks are pending
build-test / Build the x86 ubuntu 22.04 docker image (push) Waiting to run
build-test / Test ubuntu x86 docker image (push) Blocked by required conditions
build-test / Build the ARM ubuntu 22.04 docker image (push) Waiting to run
build-test / Test ubuntu ARM docker image (push) Blocked by required conditions
Some checks are pending
build-test / Build the x86 ubuntu 22.04 docker image (push) Waiting to run
build-test / Test ubuntu x86 docker image (push) Blocked by required conditions
build-test / Build the ARM ubuntu 22.04 docker image (push) Waiting to run
build-test / Test ubuntu ARM docker image (push) Blocked by required conditions
Implement RFC8781 (NAT64 prefix in RA's)
This commit is contained in:
commit
87923c8cb0
|
@ -204,6 +204,23 @@ Router Advertisement
|
|||
|
||||
Default: do not emit DNSSL option
|
||||
|
||||
.. clicmd:: ipv6 nd nat64 [X:X::X:X/M] [lifetime (0-65535)]
|
||||
|
||||
Include in RAs an advertisement of the NAT64 prefix in use (RFC8781).
|
||||
(May be configured multiple times for multiple prefixes.)
|
||||
|
||||
If no prefix is given when configuring, the NAT64 default prefix of
|
||||
64:ff9b::/96 is substituted. Only prefixes with a prefix length of /96,
|
||||
/64, /56, /48, /40 or /32 can be encoded into advertisements.
|
||||
|
||||
Lifetime is specified in seconds and defaults to ``3 * ra-interval``. If
|
||||
no value is configured, this is adjusted when ``ra-interval`` is changed.
|
||||
A lifetime of 0 seconds is used to signal NAT64 prefixes that are no longer
|
||||
valid. Note that this is rounded up to multiples of 8 seconds as a
|
||||
limitation of the option encoding.
|
||||
|
||||
Default: don't advertise any NAT64 prefix.
|
||||
|
||||
Router Advertisement Configuration Example
|
||||
==========================================
|
||||
A small example:
|
||||
|
|
19
tests/topotests/zebra_pref64/r1/frr.conf
Normal file
19
tests/topotests/zebra_pref64/r1/frr.conf
Normal file
|
@ -0,0 +1,19 @@
|
|||
log timestamp precision 6
|
||||
log file frr.log
|
||||
|
||||
interface r1-eth0
|
||||
ip address 1.1.1.1/24
|
||||
ipv6 address 2001:1111::1/64
|
||||
ipv6 nd nat64
|
||||
no ipv6 nd suppress-ra
|
||||
ipv6 nd ra-interval 3
|
||||
exit
|
||||
|
||||
interface r1-eth1
|
||||
ip address 2.2.2.1/24
|
||||
ipv6 address 2002:2222::1/64
|
||||
ipv6 nd nat64 64:ff9b::3/64 lifetime 15
|
||||
no ipv6 nd suppress-ra
|
||||
ipv6 nd ra-interval 3
|
||||
exit
|
||||
|
0
tests/topotests/zebra_pref64/r2/frr.conf
Normal file
0
tests/topotests/zebra_pref64/r2/frr.conf
Normal file
67
tests/topotests/zebra_pref64/rx_ipv6_ra_8781.py
Executable file
67
tests/topotests/zebra_pref64/rx_ipv6_ra_8781.py
Executable file
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: ISC
|
||||
# Copyright (c) 2025 by David Lamparter for NetDEF, Inc.
|
||||
|
||||
# minimal tool to receive IPv6 RAs and check for PREF64 option
|
||||
# usage:
|
||||
# python3 rx_ipv6_ra_8781.py eth123 64:ff9b::/64 1200 5
|
||||
# LIFETIME (first number) is the value expected in the packet
|
||||
# TIMEOUT (second number) is how long to wait for a matching packet
|
||||
|
||||
import sys
|
||||
import socket
|
||||
import time
|
||||
|
||||
from scapy.config import conf
|
||||
from scapy.layers.inet6 import (
|
||||
IPv6,
|
||||
ICMPv6ND_RA,
|
||||
ICMPv6NDOptPREF64,
|
||||
)
|
||||
|
||||
assert len(sys.argv) == 5, "required arguments: IFNAME PREF64 LIFETIME TIMEOUT"
|
||||
|
||||
sock = conf.L2socket(iface=sys.argv[1])
|
||||
|
||||
pref64str, masklenstr = sys.argv[2].split("/")
|
||||
pref64 = socket.inet_pton(socket.AF_INET6, pref64str)
|
||||
masklen = int(masklenstr)
|
||||
# lifetime is 13 bits with a *8
|
||||
lifetime = int(sys.argv[3]) // 8
|
||||
|
||||
timeout = float(sys.argv[4])
|
||||
|
||||
deadline = time.time() + timeout
|
||||
|
||||
while time.time() < deadline:
|
||||
pkts = sock.sniff(timeout=min(deadline - time.time(), 0.25))
|
||||
for pkt in pkts:
|
||||
ra = pkt.getlayer(ICMPv6ND_RA)
|
||||
if not ra:
|
||||
continue
|
||||
|
||||
ra.show()
|
||||
|
||||
pl = ra.payload
|
||||
while pl:
|
||||
cur, pl = pl, pl.payload
|
||||
if isinstance(cur, ICMPv6NDOptPREF64):
|
||||
cmp_pref64 = socket.inet_pton(socket.AF_INET6, cur.prefix)
|
||||
cmp_masklen = int(cur.sprintf("%plc%")[1:])
|
||||
if pref64 != cmp_pref64:
|
||||
print(f"prefix mismatch {pref64!r} != {cmp_pref64!r}")
|
||||
continue
|
||||
if masklen != cmp_masklen:
|
||||
print(f"prefixlen mismatch {masklen!r} != {cmp_masklen!r}")
|
||||
continue
|
||||
if lifetime != cur.scaledlifetime:
|
||||
print(
|
||||
f"lifetime mismatch {lifetime*8!r} != {cur.scaledlifetime*8!r}"
|
||||
)
|
||||
continue
|
||||
|
||||
print("MATCH - exiting successfully")
|
||||
sys.exit(0)
|
||||
|
||||
print("no matching packet received - exiting with failure")
|
||||
sys.exit(1)
|
57
tests/topotests/zebra_pref64/test_zebra_prefix64.py
Normal file
57
tests/topotests/zebra_pref64/test_zebra_prefix64.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 eval: (blacken-mode 1) -*-
|
||||
# SPDX-License-Identifier: ISC
|
||||
#
|
||||
# Copyright (c) 2025 Nvidia Inc.
|
||||
# Donald Sharp
|
||||
#
|
||||
"""
|
||||
Test zebra ipv6 nd nat64 advertisement
|
||||
|
||||
Requires scapy 2.6.1 or greater
|
||||
"""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import json
|
||||
from lib.topogen import Topogen
|
||||
from lib.topolog import logger
|
||||
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
pytestmark = [pytest.mark.mgmtd]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def tgen(request):
|
||||
"Setup/Teardown the environment and provide tgen argument to tests"
|
||||
|
||||
topodef = {"s1": ("r1", "r2"), "s2": ("r1", "r2")}
|
||||
|
||||
tgen = Topogen(topodef, request.module.__name__)
|
||||
tgen.start_topology()
|
||||
|
||||
router_list = tgen.routers()
|
||||
for rname, router in router_list.items():
|
||||
router.load_frr_config("frr.conf")
|
||||
|
||||
tgen.start_router()
|
||||
yield tgen
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
def test_zebra_rapref64_sent(tgen):
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
r2 = tgen.gears["r2"]
|
||||
|
||||
r2.cmd_raises("{}/rx_ipv6_ra_8781.py r2-eth0 64:ff9b::/96 16 10".format(CWD))
|
||||
r2.cmd_raises("{}/rx_ipv6_ra_8781.py r2-eth1 64:ff9b::/64 16 10".format(CWD))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
|
||||
# retval = pytest.main(["-s", "--tb=no"])
|
||||
retval = pytest.main(["-s"])
|
||||
sys.exit(retval)
|
|
@ -195,6 +195,16 @@ module frr-zebra {
|
|||
"Type for VTEP flood type.";
|
||||
}
|
||||
|
||||
/* PREF64 only accepts specific prefix lengths */
|
||||
typedef pref64-prefix {
|
||||
type inet:ipv6-prefix {
|
||||
/* rely on inet:ipv6-prefix enforcing validity already */
|
||||
pattern '.*/(96|64|56|48|40|32)';
|
||||
}
|
||||
description
|
||||
"An IPv6 prefix suitable for PREF64 announcement";
|
||||
}
|
||||
|
||||
/*
|
||||
* Common route data, shared by v4 and v6 routes.
|
||||
*/
|
||||
|
@ -2829,6 +2839,31 @@ module frr-zebra {
|
|||
}
|
||||
}
|
||||
}
|
||||
container pref64 {
|
||||
description
|
||||
"A list of NAT64 prefixes that are placed in the PREF64 option in
|
||||
Router Advertisement messages sent from the interface.";
|
||||
reference
|
||||
"RFC 8781: Discovering PREF64 in Router Advertisements";
|
||||
list pref64-prefix {
|
||||
key "prefix";
|
||||
description
|
||||
"NAT64 prefix details";
|
||||
leaf prefix {
|
||||
type pref64-prefix;
|
||||
description
|
||||
"NAT64 prefix, typically 64:ff9b::/96";
|
||||
}
|
||||
leaf lifetime {
|
||||
type uint16;
|
||||
units "seconds";
|
||||
description
|
||||
"Lifetime of the NAT64 prefix to be placed in RAs.
|
||||
If omitted, the lifetime will be calculated automatically as
|
||||
MaxRtrAdvInterval * 3";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
leaf ptm-enable {
|
||||
if-feature ptm-bfd;
|
||||
|
|
114
zebra/rtadv.c
114
zebra/rtadv.c
|
@ -95,6 +95,14 @@ DECLARE_RBTREE_UNIQ(rtadv_prefixes, struct rtadv_prefix, item,
|
|||
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS");
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL");
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREF64, "Router Advertisement NAT64 Prefix");
|
||||
|
||||
static int pref64_cmp(const struct pref64_adv *a, const struct pref64_adv *b)
|
||||
{
|
||||
return prefix_cmp(&a->p, &b->p);
|
||||
}
|
||||
|
||||
DECLARE_SORTLIST_UNIQ(pref64_advs, struct pref64_adv, itm, pref64_cmp);
|
||||
|
||||
/* Order is intentional. Matches RFC4191. This array is also used for
|
||||
command matching, so only modify with care. */
|
||||
|
@ -110,6 +118,29 @@ enum rtadv_event {
|
|||
RTADV_READ
|
||||
};
|
||||
|
||||
#define PREF64_INVALID_PREFIXLEN 0xff
|
||||
|
||||
/* RFC8781 NAT64 prefix can encode /96, /64, /56, /48, /40 and /32 only. */
|
||||
static uint8_t pref64_get_plc(const struct prefix_ipv6 *p)
|
||||
{
|
||||
switch (p->prefixlen) {
|
||||
case 96:
|
||||
return 0;
|
||||
case 64:
|
||||
return 1;
|
||||
case 56:
|
||||
return 2;
|
||||
case 48:
|
||||
return 3;
|
||||
case 40:
|
||||
return 4;
|
||||
case 32:
|
||||
return 5;
|
||||
default:
|
||||
return PREF64_INVALID_PREFIXLEN;
|
||||
}
|
||||
}
|
||||
|
||||
static void rtadv_event(struct zebra_vrf *, enum rtadv_event, int);
|
||||
|
||||
static int if_join_all_router(int, struct interface *);
|
||||
|
@ -444,6 +475,50 @@ static void rtadv_send_packet(int sock, struct interface *ifp,
|
|||
buf[len++] = '\0';
|
||||
}
|
||||
|
||||
struct pref64_adv *pref64_adv;
|
||||
|
||||
frr_each (pref64_advs, zif->rtadv.pref64_advs, pref64_adv) {
|
||||
struct nd_opt_pref64__frr *opt;
|
||||
size_t opt_len = sizeof(*opt);
|
||||
uint16_t lifetime_plc;
|
||||
|
||||
if (len + opt_len > max_len) {
|
||||
zlog_warn("%s(%u): Tx RA: NAT64 option would exceed MTU, omitting it",
|
||||
ifp->name, ifp->ifindex);
|
||||
goto no_more_opts;
|
||||
}
|
||||
|
||||
if (pref64_adv->lifetime == PREF64_LIFETIME_AUTO) {
|
||||
/* starting in msec, so won't fit in 16bit */
|
||||
unsigned lifetime;
|
||||
|
||||
lifetime = zif->rtadv.MaxRtrAdvInterval * 3;
|
||||
lifetime += 999;
|
||||
lifetime /= 1000;
|
||||
|
||||
if (lifetime > 65535)
|
||||
lifetime = 65535;
|
||||
|
||||
lifetime_plc = lifetime;
|
||||
} else
|
||||
lifetime_plc = pref64_adv->lifetime;
|
||||
|
||||
/* rounding up to 8 sec, cap at 16 bits, and clear PLC */
|
||||
lifetime_plc = MIN(lifetime_plc + 0x7, 0xffffU) & ~0x7U;
|
||||
lifetime_plc |= pref64_get_plc(&pref64_adv->p);
|
||||
|
||||
opt = (struct nd_opt_pref64__frr *)(buf + len);
|
||||
memset(opt, 0, opt_len);
|
||||
|
||||
opt->nd_opt_pref64_type = ND_OPT_PREF64;
|
||||
opt->nd_opt_pref64_len = opt_len / 8;
|
||||
opt->nd_opt_pref64_lifetime_plc = htons(lifetime_plc);
|
||||
memcpy(opt->nd_opt_pref64_prefix, &pref64_adv->p.prefix,
|
||||
sizeof(opt->nd_opt_pref64_prefix));
|
||||
|
||||
len += opt_len;
|
||||
}
|
||||
|
||||
no_more_opts:
|
||||
|
||||
msg.msg_name = (void *)&addr;
|
||||
|
@ -1723,6 +1798,41 @@ int rtadv_dnssl_encode(uint8_t *out, const char *in)
|
|||
return outp;
|
||||
}
|
||||
|
||||
struct pref64_adv *rtadv_pref64_set(struct zebra_if *zif, struct prefix_ipv6 *p, uint32_t lifetime)
|
||||
{
|
||||
struct pref64_adv *item, dummy = {};
|
||||
|
||||
prefix_copy(&dummy.p, p);
|
||||
apply_mask_ipv6(&dummy.p);
|
||||
|
||||
item = pref64_advs_find(zif->rtadv.pref64_advs, &dummy);
|
||||
if (!item) {
|
||||
item = XCALLOC(MTYPE_RTADV_PREF64, sizeof(*item));
|
||||
prefix_copy(&item->p, &dummy.p);
|
||||
|
||||
pref64_advs_add(zif->rtadv.pref64_advs, item);
|
||||
}
|
||||
|
||||
item->lifetime = lifetime;
|
||||
return item;
|
||||
}
|
||||
|
||||
static void rtadv_pref64_free(struct pref64_adv *item)
|
||||
{
|
||||
XFREE(MTYPE_RTADV_PREF64, item);
|
||||
}
|
||||
|
||||
void rtadv_pref64_update(struct zebra_if *zif, struct pref64_adv *item, uint32_t lifetime)
|
||||
{
|
||||
item->lifetime = lifetime;
|
||||
}
|
||||
|
||||
void rtadv_pref64_reset(struct zebra_if *zif, struct pref64_adv *item)
|
||||
{
|
||||
pref64_advs_del(zif->rtadv.pref64_advs, item);
|
||||
rtadv_pref64_free(item);
|
||||
}
|
||||
|
||||
/* Dump interface ND information to vty. */
|
||||
static int nd_dump_vty(struct vty *vty, json_object *json_if, struct interface *ifp)
|
||||
{
|
||||
|
@ -1956,12 +2066,16 @@ void rtadv_if_fini(struct zebra_if *zif)
|
|||
{
|
||||
struct rtadvconf *rtadv;
|
||||
struct rtadv_prefix *rp;
|
||||
struct pref64_adv *pref64_adv;
|
||||
|
||||
rtadv = &zif->rtadv;
|
||||
|
||||
while ((rp = rtadv_prefixes_pop(rtadv->prefixes)))
|
||||
rtadv_prefix_free(rp);
|
||||
|
||||
while ((pref64_adv = pref64_advs_pop(rtadv->pref64_advs)))
|
||||
rtadv_pref64_free(pref64_adv);
|
||||
|
||||
list_delete(&rtadv->AdvRDNSSList);
|
||||
list_delete(&rtadv->AdvDNSSLList);
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ struct rtadv {
|
|||
};
|
||||
|
||||
PREDECL_RBTREE_UNIQ(rtadv_prefixes);
|
||||
PREDECL_SORTLIST_UNIQ(pref64_advs);
|
||||
|
||||
/* Router advertisement parameter. From RFC4861, RFC6275 and RFC4191. */
|
||||
struct rtadvconf {
|
||||
|
@ -189,6 +190,9 @@ struct rtadvconf {
|
|||
*/
|
||||
struct list *AdvDNSSLList;
|
||||
|
||||
/* NAT64 prefix advertisements [RFC8781] */
|
||||
struct pref64_advs_head pref64_advs[1];
|
||||
|
||||
/*
|
||||
* rfc4861 states RAs must be sent at least 3 seconds apart.
|
||||
* We allow faster retransmits to speed up convergence but can
|
||||
|
@ -333,6 +337,9 @@ struct nd_opt_homeagent_info { /* Home Agent info */
|
|||
#ifndef ND_OPT_DNSSL
|
||||
#define ND_OPT_DNSSL 31
|
||||
#endif
|
||||
#ifndef ND_OPT_PREF64
|
||||
#define ND_OPT_PREF64 38
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRUCT_ND_OPT_RDNSS
|
||||
struct nd_opt_rdnss { /* Recursive DNS server option [RFC8106 5.1] */
|
||||
|
@ -358,6 +365,27 @@ struct nd_opt_dnssl { /* DNS search list option [RFC8106 5.2] */
|
|||
} __attribute__((__packed__));
|
||||
#endif
|
||||
|
||||
/* not in a system header (yet?)
|
||||
* => added "__frr" to avoid future conflicts
|
||||
*/
|
||||
struct nd_opt_pref64__frr {
|
||||
uint8_t nd_opt_pref64_type;
|
||||
uint8_t nd_opt_pref64_len;
|
||||
uint16_t nd_opt_pref64_lifetime_plc;
|
||||
uint8_t nd_opt_pref64_prefix[12]; /* highest 96 bits only */
|
||||
} __attribute__((__packed__));
|
||||
|
||||
|
||||
#define PREF64_LIFETIME_AUTO UINT32_MAX
|
||||
#define PREF64_DFLT_PREFIX "64:ff9b::/96"
|
||||
|
||||
struct pref64_adv {
|
||||
struct pref64_advs_item itm;
|
||||
|
||||
struct prefix_ipv6 p;
|
||||
uint32_t lifetime;
|
||||
};
|
||||
|
||||
/*
|
||||
* ipv6 nd prefixes can be manually defined, derived from the kernel interface
|
||||
* configs or both. If both, manual flag/timer settings are used.
|
||||
|
@ -405,6 +433,26 @@ struct rtadv_dnssl *rtadv_dnssl_set(struct zebra_if *zif,
|
|||
void rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *p);
|
||||
int rtadv_dnssl_encode(uint8_t *out, const char *in);
|
||||
|
||||
/* lifetime: 0-65535 or PREF64_LIFETIME_AUTO */
|
||||
static inline bool rtadv_pref64_valid_prefix(const struct prefix_ipv6 *p)
|
||||
{
|
||||
switch (p->prefixlen) {
|
||||
case 96:
|
||||
case 64:
|
||||
case 56:
|
||||
case 48:
|
||||
case 40:
|
||||
case 32:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct pref64_adv *rtadv_pref64_set(struct zebra_if *zif, struct prefix_ipv6 *p, uint32_t lifetime);
|
||||
void rtadv_pref64_update(struct zebra_if *zif, struct pref64_adv *item, uint32_t lifetime);
|
||||
void rtadv_pref64_reset(struct zebra_if *zif, struct pref64_adv *item);
|
||||
|
||||
void ipv6_nd_suppress_ra_set(struct interface *ifp,
|
||||
enum ipv6_nd_suppress_ra_status status);
|
||||
void ipv6_nd_interval_set(struct interface *ifp, uint32_t interval);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "northbound_cli.h"
|
||||
#include "vrf.h"
|
||||
|
||||
#include "zebra/rtadv.h"
|
||||
#include "zebra_cli.h"
|
||||
#include "zebra/zebra_cli_clippy.c"
|
||||
|
||||
|
@ -1823,6 +1824,58 @@ lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_cli_write(
|
|||
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
DEFPY_YANG(
|
||||
ipv6_nd_pref64,
|
||||
ipv6_nd_pref64_cmd,
|
||||
"[no] ipv6 nd nat64 [X:X::X:X/M]$prefix [lifetime <(0-65535)|auto>]",
|
||||
NO_STR
|
||||
"Interface IPv6 config commands\n"
|
||||
"Neighbor discovery\n"
|
||||
"NAT64 prefix advertisement (RFC8781)\n"
|
||||
"NAT64 prefix to advertise (default: 64:ff9b::/96)\n"
|
||||
"Specify validity lifetime\n"
|
||||
"Valid lifetime in seconds\n"
|
||||
"Calculate lifetime automatically\n")
|
||||
{
|
||||
if (!prefix_str)
|
||||
prefix_str = PREF64_DFLT_PREFIX;
|
||||
else if (!rtadv_pref64_valid_prefix(prefix)) {
|
||||
vty_out(vty,
|
||||
"Invalid NAT64 prefix length - must be /96, /64, /56, /48, /40 or /32\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
if (!no) {
|
||||
nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
|
||||
if (lifetime_str && strcmp(lifetime_str, "auto")) {
|
||||
nb_cli_enqueue_change(vty, "./lifetime", NB_OP_MODIFY, lifetime_str);
|
||||
} else {
|
||||
nb_cli_enqueue_change(vty, "./lifetime", NB_OP_DESTROY, NULL);
|
||||
}
|
||||
} else {
|
||||
nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
|
||||
}
|
||||
return nb_cli_apply_changes(vty,
|
||||
"./frr-zebra:zebra/ipv6-router-advertisements/pref64/pref64-prefix[prefix='%s']",
|
||||
prefix_str);
|
||||
}
|
||||
|
||||
static void lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_cli_write(
|
||||
struct vty *vty, const struct lyd_node *dnode, bool show_defaults)
|
||||
{
|
||||
const char *prefix = yang_dnode_get_string(dnode, "prefix");
|
||||
|
||||
vty_out(vty, " ipv6 nd nat64 %s", prefix);
|
||||
|
||||
if (yang_dnode_exists(dnode, "lifetime")) {
|
||||
uint16_t lifetime = yang_dnode_get_uint16(dnode, "lifetime");
|
||||
|
||||
vty_out(vty, " %u", lifetime);
|
||||
}
|
||||
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
#endif /* HAVE_RTADV */
|
||||
|
||||
#if HAVE_BFDD == 0
|
||||
|
@ -2874,6 +2927,10 @@ const struct frr_yang_module_info frr_zebra_cli_info = {
|
|||
.xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address",
|
||||
.cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_cli_write,
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/pref64/pref64-prefix",
|
||||
.cbs.cli_show = lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_cli_write,
|
||||
},
|
||||
#endif /* defined(HAVE_RTADV) */
|
||||
#if HAVE_BFDD == 0
|
||||
{
|
||||
|
@ -2989,6 +3046,7 @@ void zebra_cli_init(void)
|
|||
install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd);
|
||||
install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd);
|
||||
install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd);
|
||||
install_element(INTERFACE_NODE, &ipv6_nd_pref64_cmd);
|
||||
#endif
|
||||
#if HAVE_BFDD == 0
|
||||
install_element(INTERFACE_NODE, &zebra_ptm_enable_if_cmd);
|
||||
|
|
|
@ -763,6 +763,20 @@ const struct frr_yang_module_info frr_zebra_info = {
|
|||
.destroy = lib_interface_zebra_ipv6_router_advertisements_rdnss_rdnss_address_lifetime_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/pref64/pref64-prefix",
|
||||
.cbs = {
|
||||
.create = lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_create,
|
||||
.destroy = lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/pref64/pref64-prefix/lifetime",
|
||||
.cbs = {
|
||||
.modify = lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_lifetime_modify,
|
||||
.destroy = lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_lifetime_destroy,
|
||||
}
|
||||
},
|
||||
#endif /* defined(HAVE_RTADV) */
|
||||
#if HAVE_BFDD == 0
|
||||
{
|
||||
|
|
|
@ -269,6 +269,14 @@ int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_m
|
|||
struct nb_cb_modify_args *args);
|
||||
int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_create(
|
||||
struct nb_cb_create_args *args);
|
||||
int lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_lifetime_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_lifetime_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
#endif /* defined(HAVE_RTADV) */
|
||||
#if HAVE_BFDD == 0
|
||||
int lib_interface_zebra_ptm_enable_modify(struct nb_cb_modify_args *args);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "libfrr.h"
|
||||
#include "lib/command.h"
|
||||
#include "lib/routemap.h"
|
||||
#include "zebra/rtadv.h"
|
||||
#include "zebra/zebra_nb.h"
|
||||
#include "zebra/rib.h"
|
||||
#include "zebra_nb.h"
|
||||
|
@ -3248,6 +3249,85 @@ int lib_interface_zebra_ipv6_router_advertisements_dnssl_dnssl_domain_lifetime_d
|
|||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/pref64/pref64-prefix
|
||||
*/
|
||||
int lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_create(
|
||||
struct nb_cb_create_args *args)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct pref64_adv *entry;
|
||||
struct prefix_ipv6 p;
|
||||
uint32_t lifetime = PREF64_LIFETIME_AUTO;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
ifp = nb_running_get_entry(args->dnode, NULL, true);
|
||||
|
||||
yang_dnode_get_ipv6p(&p, args->dnode, "prefix");
|
||||
|
||||
if (yang_dnode_exists(args->dnode, "lifetime"))
|
||||
lifetime = yang_dnode_get_uint16(args->dnode, "lifetime");
|
||||
|
||||
entry = rtadv_pref64_set(ifp->info, &p, lifetime);
|
||||
nb_running_set_entry(args->dnode, entry);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct pref64_adv *entry;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
entry = nb_running_unset_entry(args->dnode);
|
||||
ifp = nb_running_get_entry(args->dnode, NULL, true);
|
||||
|
||||
rtadv_pref64_reset(ifp->info, entry);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-interface:lib/interface/frr-zebra:zebra/ipv6-router-advertisements/rdnss/rdnss-address/lifetime
|
||||
*/
|
||||
int lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_lifetime_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct pref64_adv *entry;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
entry = nb_running_get_entry(args->dnode, NULL, true);
|
||||
ifp = nb_running_get_entry(lyd_parent(lyd_parent(args->dnode)), NULL, true);
|
||||
|
||||
rtadv_pref64_update(ifp->info, entry, yang_dnode_get_uint16(args->dnode, NULL));
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int lib_interface_zebra_ipv6_router_advertisements_pref64_pref64_prefix_lifetime_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct pref64_adv *entry;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
entry = nb_running_get_entry(args->dnode, NULL, true);
|
||||
ifp = nb_running_get_entry(lyd_parent(lyd_parent(args->dnode)), NULL, true);
|
||||
|
||||
rtadv_pref64_update(ifp->info, entry, PREF64_LIFETIME_AUTO);
|
||||
return NB_OK;
|
||||
}
|
||||
#endif /* defined(HAVE_RTADV) */
|
||||
|
||||
#if HAVE_BFDD == 0
|
||||
|
|
Loading…
Reference in a new issue