summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgpd.c4
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c2
-rwxr-xr-xconfigure.ac3
-rw-r--r--doc/user/ipv6.rst55
-rw-r--r--eigrpd/eigrp_dump.c2
-rw-r--r--eigrpd/eigrp_hello.c2
-rw-r--r--eigrpd/eigrp_interface.c12
-rw-r--r--eigrpd/eigrp_network.c4
-rw-r--r--eigrpd/eigrp_packet.c14
-rw-r--r--eigrpd/eigrp_structs.h2
-rw-r--r--eigrpd/eigrp_topology.c2
-rw-r--r--eigrpd/eigrp_vty.c1
-rw-r--r--eigrpd/eigrp_zebra.c3
-rw-r--r--pbrd/pbr_map.c8
-rw-r--r--pbrd/pbr_zebra.c60
-rw-r--r--redhat/frr.spec.in2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py7
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py11
-rw-r--r--tests/topotests/eigrp-topo1/r1/zebra.conf1
-rwxr-xr-xtests/topotests/eigrp-topo1/test_eigrp_topo1.py10
-rw-r--r--vtysh/vtysh.c4
-rw-r--r--zebra/interface.c4
-rw-r--r--zebra/interface.h51
-rw-r--r--zebra/rtadv.c406
-rw-r--r--zebra/rtadv.h31
-rw-r--r--zebra/zebra_rib.c2
26 files changed, 648 insertions, 55 deletions
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index aceb990534..0ff9d75781 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -7857,9 +7857,11 @@ void bgp_master_init(struct thread_master *master)
*/
static void bgp_if_finish(struct bgp *bgp)
{
- struct vrf *vrf = vrf_lookup_by_id(bgp->vrf_id);
+ struct vrf *vrf;
struct interface *ifp;
+ vrf = bgp_vrf_lookup_by_instance_type(bgp);
+
if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW || !vrf)
return;
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index 13713c11f2..d621d58e48 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -1217,8 +1217,6 @@ DEFUN (vnc_nve_group_redist_bgpdirect_no_prefixlist,
if (rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi])
free(rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi]);
- route_map_counter_decrement(
- rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi]);
rfg->plist_redist_name[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL;
rfg->plist_redist[ZEBRA_ROUTE_BGP_DIRECT][afi] = NULL;
diff --git a/configure.ac b/configure.ac
index 20aa691165..936e1ccda6 100755
--- a/configure.ac
+++ b/configure.ac
@@ -1741,7 +1741,8 @@ AC_CHECK_TYPES([
vifi_t, struct sioc_vif_req, struct igmpmsg,
struct ifaliasreq, struct if6_aliasreq, struct in6_aliasreq,
struct nd_opt_adv_interval, struct rt_addrinfo,
- struct nd_opt_homeagent_info, struct nd_opt_adv_interval],
+ struct nd_opt_homeagent_info, struct nd_opt_adv_interval,
+ struct nd_opt_rdnss, struct nd_opt_dnssl],
[], [], FRR_INCLUDES)
AC_CHECK_MEMBERS([struct sockaddr.sa_len,
diff --git a/doc/user/ipv6.rst b/doc/user/ipv6.rst
index 585c3a505a..cc8fd18fee 100644
--- a/doc/user/ipv6.rst
+++ b/doc/user/ipv6.rst
@@ -179,10 +179,56 @@ Router Advertisement
hosts in proper interface configuration. The announced value is not verified
to be consistent with router interface MTU.
- Default: don't advertise any MTU option.::
- interface eth0
- no ipv6 nd suppress-ra
- ipv6 nd prefix 2001:0DB8:5009::/64
+ Default: don't advertise any MTU option.
+
+.. index::
+ single: ipv6 nd rdnss ipv6address [lifetime]
+ single: no ipv6 nd rdnss ipv6address [lifetime]
+.. clicmd:: [no] ipv6 nd rdnss ipv6address [lifetime]
+
+ Recursive DNS server address to advertise using the RDNSS (type 25) option
+ described in RFC8106. Can be specified more than once to advertise multiple
+ addresses. Note that hosts may choose to limit the number of RDNSS addresses
+ to track.
+
+ Optional parameter:
+
+ - ``lifetime``: the maximum time in seconds over which the specified address
+ may be used for domain name resolution. Value ``infinite`` represents
+ infinity (i.e. a value of all one bits (``0xffffffff``)). A value of 0
+ indicates that the address must no longer be used.
+ Range: ``(0-4294967295)`` Default: ``3 * ra-interval``
+
+ Default: do not emit RDNSS option
+
+.. index::
+ single: ipv6 nd dnssl domain-name-suffix [lifetime]
+ single: no ipv6 nd dnssl domain-name-suffix [lifetime]
+.. clicmd:: [no] ipv6 nd dnssl domain-name-suffix [lifetime]
+
+ Advertise DNS search list using the DNSSL (type 31) option described in
+ RFC8106. Specify more than once to advertise multiple domain name suffixes.
+ Host implementations may limit the number of honored search list entries.
+
+ Optional parameter:
+
+ - ``lifetime``: the maximum time in seconds over which the specified domain
+ suffix may be used in the course of name resolution. Value ``infinite``
+ represents infinity (i.e. a value of all one bits (``0xffffffff``)). A
+ value of 0 indicates that the name suffix must no longer be used.
+ Range: ``(0-4294967295)`` Default: ``3 * ra-interval``
+
+ Default: do not emit DNSSL option
+
+Router Advertisement Configuration Example
+==========================================
+A small example:
+
+.. code-block:: frr
+
+ interface eth0
+ no ipv6 nd suppress-ra
+ ipv6 nd prefix 2001:0DB8:5009::/64
.. seealso::
@@ -191,3 +237,4 @@ Router Advertisement
- :rfc:`4861` (Neighbor Discovery for IP Version 6 (IPv6))
- :rfc:`6275` (Mobility Support in IPv6)
- :rfc:`4191` (Default Router Preferences and More-Specific Routes)
+ - :rfc:`8106` (IPv6 Router Advertisement Options for DNS Configuration)
diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c
index 6033290914..583db6622d 100644
--- a/eigrpd/eigrp_dump.c
+++ b/eigrpd/eigrp_dump.c
@@ -174,7 +174,7 @@ const char *eigrp_if_ip_string(struct eigrp_interface *ei)
if (!ei)
return "inactive";
- ifaddr = ntohl(ei->address->u.prefix4.s_addr);
+ ifaddr = ntohl(ei->address.u.prefix4.s_addr);
snprintf(buf, EIGRP_IF_STRING_MAXLEN, "%u.%u.%u.%u",
(ifaddr >> 24) & 0xff, (ifaddr >> 16) & 0xff,
(ifaddr >> 8) & 0xff, ifaddr & 0xff);
diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c
index 413a35f2fa..b4d850be08 100644
--- a/eigrpd/eigrp_hello.c
+++ b/eigrpd/eigrp_hello.c
@@ -248,7 +248,7 @@ static void eigrp_peer_termination_decode(struct eigrp_neighbor *nbr,
struct TLV_Peer_Termination_type *param =
(struct TLV_Peer_Termination_type *)tlv;
- uint32_t my_ip = nbr->ei->address->u.prefix4.s_addr;
+ uint32_t my_ip = nbr->ei->address.u.prefix4.s_addr;
uint32_t received_ip = param->neighbor_ip;
if (my_ip == received_ip) {
diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c
index 4ad1005f2f..c52a98ee25 100644
--- a/eigrpd/eigrp_interface.c
+++ b/eigrpd/eigrp_interface.c
@@ -68,7 +68,7 @@ struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp,
/* Set zebra interface pointer. */
ei->ifp = ifp;
- ei->address = p;
+ prefix_copy(&ei->address, p);
ifp->info = ei;
listnode_add(eigrp->eiflist, ei);
@@ -185,7 +185,7 @@ int eigrp_if_up(struct eigrp_interface *ei)
struct prefix dest_addr;
- dest_addr = *ei->address;
+ dest_addr = ei->address;
apply_mask(&dest_addr);
pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
&dest_addr);
@@ -292,7 +292,7 @@ void eigrp_if_set_multicast(struct eigrp_interface *ei)
/* The interface should belong to the EIGRP-all-routers group.
*/
if (!ei->member_allrouters
- && (eigrp_if_add_allspfrouters(ei->eigrp, ei->address,
+ && (eigrp_if_add_allspfrouters(ei->eigrp, &ei->address,
ei->ifp->ifindex)
>= 0))
/* Set the flag only if the system call to join
@@ -303,7 +303,7 @@ void eigrp_if_set_multicast(struct eigrp_interface *ei)
* group. */
if (ei->member_allrouters) {
/* Only actually drop if this is the last reference */
- eigrp_if_drop_allspfrouters(ei->eigrp, ei->address,
+ eigrp_if_drop_allspfrouters(ei->eigrp, &ei->address,
ei->ifp->ifindex);
/* Unset the flag regardless of whether the system call
to leave
@@ -339,7 +339,7 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
}
- dest_addr = *ei->address;
+ dest_addr = ei->address;
apply_mask(&dest_addr);
pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
&dest_addr);
@@ -375,7 +375,7 @@ struct eigrp_interface *eigrp_if_lookup_by_local_addr(struct eigrp *eigrp,
if (ifp && ei->ifp != ifp)
continue;
- if (IPV4_ADDR_SAME(&address, &ei->address->u.prefix4))
+ if (IPV4_ADDR_SAME(&address, &ei->address.u.prefix4))
return ei;
}
diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c
index 6bb619f0e1..76f8cfc93b 100644
--- a/eigrpd/eigrp_network.c
+++ b/eigrpd/eigrp_network.c
@@ -293,7 +293,7 @@ void eigrp_if_update(struct interface *ifp)
*/
for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) {
/* EIGRP must be on and Router-ID must be configured. */
- if (!eigrp || eigrp->router_id.s_addr == 0)
+ if (eigrp->router_id.s_addr == 0)
continue;
/* Run each network for this interface. */
@@ -333,7 +333,7 @@ int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p)
if (rn->info == NULL)
continue;
- if (eigrp_network_match_iface(ei->address, &rn->p)) {
+ if (eigrp_network_match_iface(&ei->address, &rn->p)) {
found = true;
route_unlock_node(rn);
break;
diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c
index ee0476b28d..bedaf15c47 100644
--- a/eigrpd/eigrp_packet.c
+++ b/eigrpd/eigrp_packet.c
@@ -281,7 +281,7 @@ int eigrp_make_sha256_digest(struct eigrp_interface *ei, struct stream *s,
return 0;
}
- inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, PREFIX_STRLEN);
+ inet_ntop(AF_INET, &ei->address.u.prefix4, source_ip, PREFIX_STRLEN);
memset(&ctx, 0, sizeof(ctx));
buffer[0] = '\n';
@@ -362,7 +362,7 @@ int eigrp_write(struct thread *thread)
}
if (ep->dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS))
- eigrp_if_ipmulticast(eigrp, ei->address, ei->ifp->ifindex);
+ eigrp_if_ipmulticast(eigrp, &ei->address, ei->ifp->ifindex);
memset(&iph, 0, sizeof(struct ip));
memset(&sa_dst, 0, sizeof(sa_dst));
@@ -418,7 +418,7 @@ int eigrp_write(struct thread *thread)
iph.ip_ttl = EIGRP_IP_TTL;
iph.ip_p = IPPROTO_EIGRPIGP;
iph.ip_sum = 0;
- iph.ip_src.s_addr = ei->address->u.prefix4.s_addr;
+ iph.ip_src.s_addr = ei->address.u.prefix4.s_addr;
iph.ip_dst.s_addr = ep->dst.s_addr;
memset(&msg, 0, sizeof(msg));
@@ -547,7 +547,7 @@ int eigrp_read(struct thread *thread)
/* Self-originated packet should be discarded silently. */
if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src)
- || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address->u.prefix4))) {
+ || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address.u.prefix4))) {
if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
zlog_debug(
"eigrp_read[%s]: Dropping self-originated packet",
@@ -581,7 +581,7 @@ int eigrp_read(struct thread *thread)
sizeof(buf[0])),
inet_ntop(AF_INET, &iph->ip_dst, buf[1],
sizeof(buf[1])),
- inet_ntop(AF_INET, &ei->address->u.prefix4,
+ inet_ntop(AF_INET, &ei->address.u.prefix4,
buf[2], sizeof(buf[2])));
if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) {
@@ -981,9 +981,9 @@ static int eigrp_check_network_mask(struct eigrp_interface *ei,
if (ei->type == EIGRP_IFTYPE_POINTOPOINT)
return 1;
- masklen2ip(ei->address->prefixlen, &mask);
+ masklen2ip(ei->address.prefixlen, &mask);
- me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr;
+ me.s_addr = ei->address.u.prefix4.s_addr & mask.s_addr;
him.s_addr = ip_src.s_addr & mask.s_addr;
if (IPV4_ADDR_SAME(&me, &him))
diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h
index 644ab0829f..a78e5a53cf 100644
--- a/eigrpd/eigrp_structs.h
+++ b/eigrpd/eigrp_structs.h
@@ -180,7 +180,7 @@ struct eigrp_interface {
/* EIGRP Network Type. */
uint8_t type;
- struct prefix *address; /* Interface prefix */
+ struct prefix address; /* Interface prefix */
/* Neighbor information. */
struct list *nbrs; /* EIGRP Neighbor List */
diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c
index 23f5a705eb..e861cdb333 100644
--- a/eigrpd/eigrp_topology.c
+++ b/eigrpd/eigrp_topology.c
@@ -141,10 +141,10 @@ void eigrp_prefix_entry_add(struct route_table *topology,
__PRETTY_FUNCTION__,
prefix2str(pe->destination, buf, sizeof(buf)));
}
+ route_unlock_node(rn);
}
rn->info = pe;
- route_lock_node(rn);
}
/*
diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c
index 104f35244e..a9b103de47 100644
--- a/eigrpd/eigrp_vty.c
+++ b/eigrpd/eigrp_vty.c
@@ -559,6 +559,7 @@ DEFPY (show_ip_eigrp_topology,
tn = rn->info;
eigrp_vty_display_prefix_entry(vty, eigrp, tn, argc == 5);
+ route_unlock_node(rn);
return CMD_SUCCESS;
}
diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c
index 09d876afaa..dc1ae675b0 100644
--- a/eigrpd/eigrp_zebra.c
+++ b/eigrpd/eigrp_zebra.c
@@ -258,7 +258,8 @@ static int eigrp_interface_address_delete(int command, struct zclient *zclient,
return 0;
/* Call interface hook functions to clean up */
- eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA);
+ if (prefix_cmp(&ei->address, c->address) == 0)
+ eigrp_if_free(ei, INTERFACE_DOWN_BY_ZEBRA);
connected_free(c);
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
index eb2c082fb9..950ce8dfe1 100644
--- a/pbrd/pbr_map.c
+++ b/pbrd/pbr_map.c
@@ -409,7 +409,8 @@ void pbr_map_schedule_policy_from_nhg(const char *nh_group)
pbrm->name);
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
DEBUGD(&pbr_dbg_map, "\tNH Grp name: %s",
- pbrms->nhgrp_name ? pbrms->nhgrp_name : "NULL");
+ pbrms->nhgrp_name ?
+ pbrms->nhgrp_name : pbrms->internal_nhg_name);
if (pbrms->nhgrp_name
&& (strcmp(nh_group, pbrms->nhgrp_name) == 0)) {
@@ -526,12 +527,9 @@ void pbr_map_check(struct pbr_map_sequence *pbrms)
DEBUGD(&pbr_dbg_map, "%s: for %s(%u)", __PRETTY_FUNCTION__,
pbrm->name, pbrms->seqno);
if (pbr_map_check_valid(pbrm->name))
- DEBUGD(&pbr_dbg_map, "We are totally valid %s\n",
+ DEBUGD(&pbr_dbg_map, "We are totally valid %s",
pbrm->name);
- DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64,
- __PRETTY_FUNCTION__, pbrm->name, pbrms->seqno, pbrms->reason);
-
if (pbrms->reason == PBR_MAP_VALID_SEQUENCE_NUMBER) {
install = true;
DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64,
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c
index 7974bbfb4e..425bc04b4d 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -69,6 +69,9 @@ static int interface_add(int command, struct zclient *zclient,
if (!ifp)
return 0;
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s", __PRETTY_FUNCTION__, ifp->name);
+
if (!ifp->info)
pbr_if_new(ifp);
@@ -89,6 +92,9 @@ static int interface_delete(int command, struct zclient *zclient,
if (ifp == NULL)
return 0;
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s", __PRETTY_FUNCTION__, ifp->name);
+
if_set_index(ifp, IFINDEX_INTERNAL);
return 0;
@@ -97,7 +103,14 @@ static int interface_delete(int command, struct zclient *zclient,
static int interface_address_add(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
- zebra_interface_address_read(command, zclient->ibuf, vrf_id);
+ struct connected *c;
+ char buf[PREFIX_STRLEN];
+
+ c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
+
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s added %s", __PRETTY_FUNCTION__, c->ifp->name,
+ prefix2str(c->address, buf, sizeof(buf)));
return 0;
}
@@ -106,12 +119,17 @@ static int interface_address_delete(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
struct connected *c;
+ char buf[PREFIX_STRLEN];
c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
if (!c)
return 0;
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s deleted %s", __PRETTY_FUNCTION__, c->ifp->name,
+ prefix2str(c->address, buf, sizeof(buf)));
+
connected_free(c);
return 0;
}
@@ -119,8 +137,12 @@ static int interface_address_delete(int command, struct zclient *zclient,
static int interface_state_up(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
+ struct interface *ifp;
+
+ ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
- zebra_interface_state_read(zclient->ibuf, vrf_id);
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s is up", __PRETTY_FUNCTION__, ifp->name);
return 0;
}
@@ -128,8 +150,12 @@ static int interface_state_up(int command, struct zclient *zclient,
static int interface_state_down(int command, struct zclient *zclient,
zebra_size_t length, vrf_id_t vrf_id)
{
+ struct interface *ifp;
- zebra_interface_state_read(zclient->ibuf, vrf_id);
+ ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
+
+ DEBUGD(&pbr_dbg_zebra,
+ "%s: %s is down", __PRETTY_FUNCTION__, ifp->name);
return 0;
}
@@ -142,11 +168,11 @@ static int route_notify_owner(int command, struct zclient *zclient,
uint32_t table_id;
char buf[PREFIX_STRLEN];
- prefix2str(&p, buf, sizeof(buf));
-
if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, &note))
return -1;
+ prefix2str(&p, buf, sizeof(buf));
+
switch (note) {
case ZAPI_ROUTE_FAIL_INSTALL:
DEBUGD(&pbr_dbg_zebra,
@@ -207,20 +233,20 @@ static int rule_notify_owner(int command, struct zclient *zclient,
switch (note) {
case ZAPI_RULE_FAIL_INSTALL:
- DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_FAIL_INSTALL",
- __PRETTY_FUNCTION__);
pbrms->installed &= ~installed;
+ DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_FAIL_INSTALL: %lu",
+ __PRETTY_FUNCTION__, pbrms->installed);
break;
case ZAPI_RULE_INSTALLED:
pbrms->installed |= installed;
- DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED",
- __PRETTY_FUNCTION__);
+ DEBUGD(&pbr_dbg_zebra, "%s: Received RULE_INSTALLED: %lu",
+ __PRETTY_FUNCTION__, pbrms->installed);
break;
case ZAPI_RULE_FAIL_REMOVE:
case ZAPI_RULE_REMOVED:
pbrms->installed &= ~installed;
- DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED",
- __PRETTY_FUNCTION__);
+ DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED: %lu",
+ __PRETTY_FUNCTION__, pbrms->installed);
break;
}
@@ -229,6 +255,8 @@ static int rule_notify_owner(int command, struct zclient *zclient,
static void zebra_connected(struct zclient *zclient)
{
+ DEBUGD(&pbr_dbg_zebra, "%s: Registering for fun and profit",
+ __PRETTY_FUNCTION__);
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
@@ -236,11 +264,15 @@ static void route_add_helper(struct zapi_route *api, struct nexthop_group nhg,
uint8_t install_afi)
{
struct zapi_nexthop *api_nh;
+ char buf[PREFIX_STRLEN];
struct nexthop *nhop;
int i;
api->prefix.family = install_afi;
+ DEBUGD(&pbr_dbg_zebra, "\tEncoding %s",
+ prefix2str(&api->prefix, buf, sizeof(buf)));
+
i = 0;
for (ALL_NEXTHOPS(nhg, nhop)) {
api_nh = &api->nexthops[i];
@@ -284,6 +316,9 @@ void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg,
{
struct zapi_route api;
+ DEBUGD(&pbr_dbg_zebra, "%s for Table: %d", __PRETTY_FUNCTION__,
+ pnhgc->table_id);
+
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
@@ -323,6 +358,9 @@ void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi)
{
struct zapi_route api;
+ DEBUGD(&pbr_dbg_zebra, "%s for Table: %d", __PRETTY_FUNCTION__,
+ pnhgc->table_id);
+
memset(&api, 0, sizeof(api));
api.vrf_id = VRF_DEFAULT;
api.type = ZEBRA_ROUTE_PBR;
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 7a6344aa4c..6d18c005b9 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -171,6 +171,7 @@ BuildRequires: python27-sphinx
BuildRequires: python-devel >= 2.7
BuildRequires: python-sphinx
%endif
+Requires: initscripts
%if %{with_pam}
BuildRequires: pam-devel
%endif
@@ -188,7 +189,6 @@ Requires(post): chkconfig
Requires(preun): chkconfig
# Initscripts > 5.60 is required for IPv6 support
Requires(pre): initscripts >= 5.60
-Requires: initscripts
%endif
Provides: routingdaemon = %{version}-%{release}
Obsoletes: gated mrt zebra frr-sysvinit
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
index 31e23faede..ce542413ba 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
@@ -141,7 +141,10 @@ class ThisTestTopo(Topo):
switch[1].add_link(tgen.gears['r2'], nodeif='r2-eth2')
switch[1].add_link(tgen.gears['r3'], nodeif='r3-eth1')
+l3mdev_accept = 0
+
def ltemplatePreRouterStartHook():
+ global l3mdev_accept
cc = ltemplateRtrCmd()
krel = platform.release()
tgen = get_topogen()
@@ -172,7 +175,7 @@ def ltemplatePreRouterStartHook():
'ip ru add oif {0}-cust1 table 10',
'ip ru add iif {0}-cust1 table 10',
'ip link set dev {0}-cust1 up',
- 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)]
+ 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)]
for rtr in rtrs:
router = tgen.gears[rtr]
for cmd in cmds:
@@ -202,7 +205,7 @@ def ltemplatePreRouterStartHook():
'ip ru add oif {0}-cust2 table 20',
'ip ru add iif {0}-cust2 table 20',
'ip link set dev {0}-cust2 up',
- 'sysctl -w net.ipv4.udp_l3mdev_accept={}'.format(l3mdev_accept)]
+ 'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept)]
for rtr in rtrs:
for cmd in cmds:
cc.doCmd(tgen, rtr, cmd.format(rtr))
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
index 778d504040..f5d73a8c49 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
@@ -1,11 +1,12 @@
from lutil import luCommand
-
-rtrs = ['r1', 'r3', 'r4', 'ce1', 'ce2', 'ce3', 'ce4']
-for rtr in rtrs:
+from customize import l3mdev_accept
+l3mdev_rtrs = ['r1', 'r3', 'r4', 'ce4']
+for rtr in l3mdev_rtrs:
luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = \d*','none','')
found = luLast()
- luCommand(rtr,'ss -aep',':bgp','pass','IPv4:bgp, l3mdev%s' % found.group(0))
- luCommand(rtr,'ss -aep',':.:bgp','pass','IPv6:bgp')
+ luCommand(rtr,'ss -naep',':179','pass','IPv4:bgp, l3mdev{}'.format(found.group(0)))
+ luCommand(rtr,'ss -naep',':.*:179','pass','IPv6:bgp')
+ luCommand(rtr,'sysctl net.ipv4.tcp_l3mdev_accept',' = {}'.format(l3mdev_accept),'pass','l3mdev matches expected (real/expected{}/{})'.format(found.group(0),l3mdev_accept))
rtrs = ['r1', 'r3', 'r4']
for rtr in rtrs:
diff --git a/tests/topotests/eigrp-topo1/r1/zebra.conf b/tests/topotests/eigrp-topo1/r1/zebra.conf
index 8537f6dd80..56ae4a66f4 100644
--- a/tests/topotests/eigrp-topo1/r1/zebra.conf
+++ b/tests/topotests/eigrp-topo1/r1/zebra.conf
@@ -1,4 +1,5 @@
log file zebra.log
+debug zebra rib detail
!
hostname r1
!
diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
index 8ea2f0b506..1c00face43 100755
--- a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
+++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
@@ -171,6 +171,16 @@ def test_zebra_ipv4_routingTable():
assertmsg = 'Zebra IPv4 Routing Table verification failed for router {}'.format(router.name)
assert topotest.json_cmp(output, expected) is None, assertmsg
+def test_shut_interface_and_recover():
+ "Test shutdown of an interface and recovery of the interface"
+
+ tgen = get_topogen()
+ router = tgen.gears['r1']
+ router.run('ip link set r1-eth1 down')
+ topotest.sleep(5, 'Waiting for EIGRP convergence')
+ router.run('ip link set r1-eth1 up')
+
+
def test_shutdown_check_stderr():
if os.environ.get('TOPOTESTS_CHECK_STDERR') is None:
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 340c9be601..41fd6ed7d6 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -3330,7 +3330,7 @@ static void vtysh_client_sorted_insert(struct vtysh_client *head_client,
#define MAXIMUM_INSTANCES 10
-static void vtysh_update_all_insances(struct vtysh_client *head_client)
+static void vtysh_update_all_instances(struct vtysh_client *head_client)
{
struct vtysh_client *client;
DIR *dir;
@@ -3373,7 +3373,7 @@ static int vtysh_connect_all_instances(struct vtysh_client *head_client)
struct vtysh_client *client;
int rc = 0;
- vtysh_update_all_insances(head_client);
+ vtysh_update_all_instances(head_client);
client = head_client->next;
while (client) {
diff --git a/zebra/interface.c b/zebra/interface.c
index c88aadc683..229f9c1da4 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -135,6 +135,8 @@ static int if_zebra_new_hook(struct interface *ifp)
rtadv->DefaultPreference = RTADV_PREF_MEDIUM;
rtadv->AdvPrefixList = list_new();
+ rtadv->AdvRDNSSList = list_new();
+ rtadv->AdvDNSSLList = list_new();
}
#endif /* HAVE_RTADV */
@@ -175,6 +177,8 @@ static int if_zebra_delete_hook(struct interface *ifp)
rtadv = &zebra_if->rtadv;
list_delete(&rtadv->AdvPrefixList);
+ list_delete(&rtadv->AdvRDNSSList);
+ list_delete(&rtadv->AdvDNSSLList);
#endif /* HAVE_RTADV */
THREAD_OFF(zebra_if->speed_update);
diff --git a/zebra/interface.h b/zebra/interface.h
index 01dd697772..1dbcf33fad 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -168,6 +168,22 @@ struct rtadvconf {
int DefaultPreference;
#define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */
+ /*
+ * List of recursive DNS servers to include in the RDNSS option.
+ * See [RFC8106 5.1]
+ *
+ * Default: empty list; do not emit RDNSS option
+ */
+ struct list *AdvRDNSSList;
+
+ /*
+ * List of DNS search domains to include in the DNSSL option.
+ * See [RFC8106 5.2]
+ *
+ * Default: empty list; do not emit DNSSL option
+ */
+ struct list *AdvDNSSLList;
+
uint8_t inFastRexmit; /* True if we're rexmits faster than usual */
/* Track if RA was configured by BGP or by the Operator or both */
@@ -182,6 +198,41 @@ struct rtadvconf {
#define RTADV_NUM_FAST_REXMITS 4 /* Fast Rexmit RA 4 times on certain events */
};
+struct rtadv_rdnss {
+ /* Address of recursive DNS server to advertise */
+ struct in6_addr addr;
+
+ /*
+ * Lifetime in seconds; all-ones means infinity, zero
+ * stop using it.
+ */
+ uint32_t lifetime;
+
+ /* If lifetime not set, use a default of 3*MaxRtrAdvInterval */
+ int lifetime_set;
+};
+
+/*
+ * [RFC1035 2.3.4] sets the maximum length of a domain name (a sequence of
+ * labels, each prefixed by a length octet) at 255 octets.
+ */
+#define RTADV_MAX_ENCODED_DOMAIN_NAME 255
+
+struct rtadv_dnssl {
+ /* Domain name without trailing root zone dot (NUL-terminated) */
+ char name[RTADV_MAX_ENCODED_DOMAIN_NAME - 1];
+
+ /* Name encoded as in [RFC1035 3.1] */
+ uint8_t encoded_name[RTADV_MAX_ENCODED_DOMAIN_NAME];
+
+ /* Actual length of encoded_name */
+ size_t encoded_len;
+
+ /* Lifetime as for RDNSS */
+ uint32_t lifetime;
+ int lifetime_set;
+};
+
#endif /* HAVE_RTADV */
/* Zebra interface type - ones of interest. */
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 86edc6fb5e..fadf8317cc 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -66,6 +66,9 @@ extern struct zebra_privs_t zserv_privs;
#define ALLNODE "ff02::1"
#define ALLROUTER "ff02::2"
+DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS")
+DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL")
+
/* Order is intentional. Matches RFC4191. This array is also used for
command matching, so only modify with care. */
const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0};
@@ -355,6 +358,78 @@ static void rtadv_send_packet(int sock, struct interface *ifp)
len += sizeof(struct nd_opt_mtu);
}
+ /*
+ * There is no limit on the number of configurable recursive DNS
+ * servers or search list entries. We don't want the RA message
+ * to exceed the link's MTU (risking fragmentation) or even
+ * blow the stack buffer allocated for it.
+ */
+ size_t max_len = MIN(ifp->mtu6 - 40, sizeof(buf));
+
+ /* Recursive DNS servers */
+ struct rtadv_rdnss *rdnss;
+
+ for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) {
+ size_t opt_len =
+ sizeof(struct nd_opt_rdnss) + sizeof(struct in6_addr);
+
+ if (len + opt_len > max_len) {
+ zlog_warn(
+ "%s(%u): Tx RA: RDNSS option would exceed MTU, omitting it",
+ ifp->name, ifp->ifindex);
+ goto no_more_opts;
+ }
+ struct nd_opt_rdnss *opt = (struct nd_opt_rdnss *)(buf + len);
+
+ opt->nd_opt_rdnss_type = ND_OPT_RDNSS;
+ opt->nd_opt_rdnss_len = opt_len / 8;
+ opt->nd_opt_rdnss_reserved = 0;
+ opt->nd_opt_rdnss_lifetime = htonl(
+ rdnss->lifetime_set
+ ? rdnss->lifetime
+ : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval));
+
+ len += sizeof(struct nd_opt_rdnss);
+
+ IPV6_ADDR_COPY(buf + len, &rdnss->addr);
+ len += sizeof(struct in6_addr);
+ }
+
+ /* DNS search list */
+ struct rtadv_dnssl *dnssl;
+
+ for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) {
+ size_t opt_len = sizeof(struct nd_opt_dnssl)
+ + ((dnssl->encoded_len + 7) & ~7);
+
+ if (len + opt_len > max_len) {
+ zlog_warn(
+ "%s(%u): Tx RA: DNSSL option would exceed MTU, omitting it",
+ ifp->name, ifp->ifindex);
+ goto no_more_opts;
+ }
+ struct nd_opt_dnssl *opt = (struct nd_opt_dnssl *)(buf + len);
+
+ opt->nd_opt_dnssl_type = ND_OPT_DNSSL;
+ opt->nd_opt_dnssl_len = opt_len / 8;
+ opt->nd_opt_dnssl_reserved = 0;
+ opt->nd_opt_dnssl_lifetime = htonl(
+ dnssl->lifetime_set
+ ? dnssl->lifetime
+ : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval));
+
+ len += sizeof(struct nd_opt_dnssl);
+
+ memcpy(buf + len, dnssl->encoded_name, dnssl->encoded_len);
+ len += dnssl->encoded_len;
+
+ /* Zero-pad to 8-octet boundary */
+ while (len % 8)
+ buf[len++] = '\0';
+ }
+
+no_more_opts:
+
msg.msg_name = (void *)&addr;
msg.msg_namelen = sizeof(struct sockaddr_in6);
msg.msg_iov = &iov;
@@ -1533,6 +1608,308 @@ DEFUN (no_ipv6_nd_mtu,
return CMD_SUCCESS;
}
+static struct rtadv_rdnss *rtadv_rdnss_new(void)
+{
+ return XCALLOC(MTYPE_RTADV_RDNSS, sizeof(struct rtadv_rdnss));
+}
+
+static void rtadv_rdnss_free(struct rtadv_rdnss *rdnss)
+{
+ XFREE(MTYPE_RTADV_RDNSS, rdnss);
+}
+
+static struct rtadv_rdnss *rtadv_rdnss_lookup(struct list *list,
+ struct rtadv_rdnss *rdnss)
+{
+ struct listnode *node;
+ struct rtadv_rdnss *p;
+
+ for (ALL_LIST_ELEMENTS_RO(list, node, p))
+ if (IPV6_ADDR_SAME(&p->addr, &rdnss->addr))
+ return p;
+ return NULL;
+}
+
+static struct rtadv_rdnss *rtadv_rdnss_get(struct list *list,
+ struct rtadv_rdnss *rdnss)
+{
+ struct rtadv_rdnss *p;
+
+ p = rtadv_rdnss_lookup(list, rdnss);
+ if (p)
+ return p;
+
+ p = rtadv_rdnss_new();
+ memcpy(p, rdnss, sizeof(struct rtadv_rdnss));
+ listnode_add(list, p);
+
+ return p;
+}
+
+static void rtadv_rdnss_set(struct zebra_if *zif, struct rtadv_rdnss *rdnss)
+{
+ struct rtadv_rdnss *p;
+
+ p = rtadv_rdnss_get(zif->rtadv.AdvRDNSSList, rdnss);
+ p->lifetime = rdnss->lifetime;
+ p->lifetime_set = rdnss->lifetime_set;
+}
+
+static int rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *rdnss)
+{
+ struct rtadv_rdnss *p;
+
+ p = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rdnss);
+ if (p) {
+ listnode_delete(zif->rtadv.AdvRDNSSList, p);
+ rtadv_rdnss_free(p);
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct rtadv_dnssl *rtadv_dnssl_new(void)
+{
+ return XCALLOC(MTYPE_RTADV_DNSSL, sizeof(struct rtadv_dnssl));
+}
+
+static void rtadv_dnssl_free(struct rtadv_dnssl *dnssl)
+{
+ XFREE(MTYPE_RTADV_DNSSL, dnssl);
+}
+
+static struct rtadv_dnssl *rtadv_dnssl_lookup(struct list *list,
+ struct rtadv_dnssl *dnssl)
+{
+ struct listnode *node;
+ struct rtadv_dnssl *p;
+
+ for (ALL_LIST_ELEMENTS_RO(list, node, p))
+ if (!strcasecmp(p->name, dnssl->name))
+ return p;
+ return NULL;
+}
+
+static struct rtadv_dnssl *rtadv_dnssl_get(struct list *list,
+ struct rtadv_dnssl *dnssl)
+{
+ struct rtadv_dnssl *p;
+
+ p = rtadv_dnssl_lookup(list, dnssl);
+ if (p)
+ return p;
+
+ p = rtadv_dnssl_new();
+ memcpy(p, dnssl, sizeof(struct rtadv_dnssl));
+ listnode_add(list, p);
+
+ return p;
+}
+
+static void rtadv_dnssl_set(struct zebra_if *zif, struct rtadv_dnssl *dnssl)
+{
+ struct rtadv_dnssl *p;
+
+ p = rtadv_dnssl_get(zif->rtadv.AdvDNSSLList, dnssl);
+ memcpy(p, dnssl, sizeof(struct rtadv_dnssl));
+}
+
+static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl)
+{
+ struct rtadv_dnssl *p;
+
+ p = rtadv_dnssl_lookup(zif->rtadv.AdvDNSSLList, dnssl);
+ if (p) {
+ listnode_delete(zif->rtadv.AdvDNSSLList, p);
+ rtadv_dnssl_free(p);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Convert dotted domain name (with or without trailing root zone dot) to
+ * sequence of length-prefixed labels, as described in [RFC1035 3.1]. Write up
+ * to strlen(in) + 2 octets to out.
+ *
+ * Returns the number of octets written to out or -1 if in does not constitute
+ * a valid domain name.
+ */
+static int rtadv_dnssl_encode(uint8_t *out, const char *in)
+{
+ const char *label_start, *label_end;
+ size_t outp;
+
+ outp = 0;
+ label_start = in;
+
+ while (*label_start) {
+ size_t label_len;
+
+ label_end = strchr(label_start, '.');
+ if (label_end == NULL)
+ label_end = label_start + strlen(label_start);
+
+ label_len = label_end - label_start;
+ if (label_len >= 64)
+ return -1; /* labels must be 63 octets or less */
+
+ out[outp++] = (uint8_t)label_len;
+ memcpy(out + outp, label_start, label_len);
+ outp += label_len;
+ label_start += label_len;
+ if (*label_start == '.')
+ label_start++;
+ }
+
+ out[outp++] = '\0';
+ return outp;
+}
+
+DEFUN(ipv6_nd_rdnss,
+ ipv6_nd_rdnss_cmd,
+ "ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]",
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "Recursive DNS server information\n"
+ "IPv6 address\n"
+ "Valid lifetime in seconds\n"
+ "Infinite valid lifetime\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *zif = ifp->info;
+ struct rtadv_rdnss rdnss = {0};
+
+ if (inet_pton(AF_INET6, argv[3]->arg, &rdnss.addr) != 1) {
+ vty_out(vty, "Malformed IPv6 address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (argc > 4) {
+ char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
+ : argv[4]->text;
+ rdnss.lifetime = strmatch(lifetime, "infinite")
+ ? UINT32_MAX
+ : strtoll(lifetime, NULL, 10);
+ rdnss.lifetime_set = 1;
+ }
+
+ rtadv_rdnss_set(zif, &rdnss);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_ipv6_nd_rdnss,
+ no_ipv6_nd_rdnss_cmd,
+ "no ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]",
+ NO_STR
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "Recursive DNS server information\n"
+ "IPv6 address\n"
+ "Valid lifetime in seconds\n"
+ "Infinite valid lifetime\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *zif = ifp->info;
+ struct rtadv_rdnss rdnss = {0};
+
+ if (inet_pton(AF_INET6, argv[4]->arg, &rdnss.addr) != 1) {
+ vty_out(vty, "Malformed IPv6 address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (rtadv_rdnss_reset(zif, &rdnss) != 1) {
+ vty_out(vty, "Non-existant RDNSS address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(ipv6_nd_dnssl,
+ ipv6_nd_dnssl_cmd,
+ "ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]",
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "DNS search list information\n"
+ "Domain name suffix\n"
+ "Valid lifetime in seconds\n"
+ "Infinite valid lifetime\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *zif = ifp->info;
+ struct rtadv_dnssl dnssl = {0};
+ size_t len;
+ int ret;
+
+ len = strlcpy(dnssl.name, argv[3]->arg, sizeof(dnssl.name));
+ if (len == 0 || len >= sizeof(dnssl.name)) {
+ vty_out(vty, "Malformed DNS search domain\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (dnssl.name[len - 1] == '.') {
+ /*
+ * Allow, but don't require, a trailing dot signifying the root
+ * zone. Canonicalize by cutting it off if present.
+ */
+ dnssl.name[len - 1] = '\0';
+ len--;
+ }
+ if (argc > 4) {
+ char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
+ : argv[4]->text;
+ dnssl.lifetime = strmatch(lifetime, "infinite")
+ ? UINT32_MAX
+ : strtoll(lifetime, NULL, 10);
+ dnssl.lifetime_set = 1;
+ }
+
+ ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name);
+ if (ret < 0) {
+ vty_out(vty, "Malformed DNS search domain\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ dnssl.encoded_len = ret;
+ rtadv_dnssl_set(zif, &dnssl);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_ipv6_nd_dnssl,
+ no_ipv6_nd_dnssl_cmd,
+ "no ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]",
+ NO_STR
+ "Interface IPv6 config commands\n"
+ "Neighbor discovery\n"
+ "DNS search list information\n"
+ "Domain name suffix\n"
+ "Valid lifetime in seconds\n"
+ "Infinite valid lifetime\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct zebra_if *zif = ifp->info;
+ struct rtadv_dnssl dnssl = {0};
+ size_t len;
+
+ len = strlcpy(dnssl.name, argv[4]->arg, sizeof(dnssl.name));
+ if (len == 0 || len >= sizeof(dnssl.name)) {
+ vty_out(vty, "Malformed DNS search domain\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (dnssl.name[len - 1] == '.') {
+ dnssl.name[len - 1] = '\0';
+ len--;
+ }
+ if (rtadv_dnssl_reset(zif, &dnssl) != 1) {
+ vty_out(vty, "Non-existant DNS search domain\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return CMD_SUCCESS;
+}
+
+
/* Dump interface ND information to vty. */
static int nd_dump_vty(struct vty *vty, struct interface *ifp)
{
@@ -1607,6 +1984,8 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp)
struct zebra_if *zif;
struct listnode *node;
struct rtadv_prefix *rprefix;
+ struct rtadv_rdnss *rdnss;
+ struct rtadv_dnssl *dnssl;
char buf[PREFIX_STRLEN];
int interval;
@@ -1688,6 +2067,29 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp)
vty_out(vty, " router-address");
vty_out(vty, "\n");
}
+ for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) {
+ char buf[INET6_ADDRSTRLEN];
+
+ vty_out(vty, " ipv6 nd rdnss %s",
+ inet_ntop(AF_INET6, &rdnss->addr, buf, sizeof(buf)));
+ if (rdnss->lifetime_set) {
+ if (rdnss->lifetime == UINT32_MAX)
+ vty_out(vty, " infinite");
+ else
+ vty_out(vty, " %u", rdnss->lifetime);
+ }
+ vty_out(vty, "\n");
+ }
+ for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) {
+ vty_out(vty, " ipv6 nd dnssl %s", dnssl->name);
+ if (dnssl->lifetime_set) {
+ if (dnssl->lifetime == UINT32_MAX)
+ vty_out(vty, " infinite");
+ else
+ vty_out(vty, " %u", dnssl->lifetime);
+ }
+ vty_out(vty, "\n");
+ }
return 0;
}
@@ -1782,6 +2184,10 @@ void rtadv_cmd_init(void)
install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd);
install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
+ install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_nd_rdnss_cmd);
+ install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_nd_dnssl_cmd);
}
static int if_join_all_router(int sock, struct interface *ifp)
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 03db13fd69..f7c27ebcb3 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -91,6 +91,37 @@ struct nd_opt_homeagent_info { /* Home Agent info */
} __attribute__((__packed__));
#endif
+#ifndef ND_OPT_RDNSS
+#define ND_OPT_RDNSS 25
+#endif
+#ifndef ND_OPT_DNSSL
+#define ND_OPT_DNSSL 31
+#endif
+
+#ifndef HAVE_STRUCT_ND_OPT_RDNSS
+struct nd_opt_rdnss { /* Recursive DNS server option [RFC8106 5.1] */
+ uint8_t nd_opt_rdnss_type;
+ uint8_t nd_opt_rdnss_len;
+ uint16_t nd_opt_rdnss_reserved;
+ uint32_t nd_opt_rdnss_lifetime;
+ /* Followed by one or more IPv6 addresses */
+} __attribute__((__packed__));
+#endif
+
+#ifndef HAVE_STRUCT_ND_OPT_DNSSL
+struct nd_opt_dnssl { /* DNS search list option [RFC8106 5.2] */
+ uint8_t nd_opt_dnssl_type;
+ uint8_t nd_opt_dnssl_len;
+ uint16_t nd_opt_dnssl_reserved;
+ uint32_t nd_opt_dnssl_lifetime;
+ /*
+ * Followed by one or more domain names encoded as in [RFC1035 3.1].
+ * Multiple domain names are concatenated after encoding. In any case,
+ * the result is zero-padded to a multiple of 8 octets.
+ */
+} __attribute__((__packed__));
+#endif
+
extern const char *rtadv_pref_strs[];
#endif /* HAVE_RTADV */
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index dcc5a7acb0..8afcc2b685 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -1089,7 +1089,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
hook_call(rib_update, rn, "installing in kernel");
/* Send add or update */
- if (old && (old != re))
+ if (old)
ret = dplane_route_update(rn, re, old);
else
ret = dplane_route_add(rn, re);