mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-16 09:21:55 +00:00
bgpd: attr changes for EAD routes
Add ESI as an inline attribute field along with the other EVPN attributes. This may be re-worked when the rest of the EVPN attributes find a new home. Some cleanup has been done to get rid of stale/unused references to ESI. And also to consolidate duplicate definitions of ES ID types. Signed-off-by: Anuradha Karuppiah <anuradhak@cumulusnetworks.com>
This commit is contained in:
parent
4248407b6d
commit
0a50c24813
@ -718,6 +718,7 @@ bool attrhash_cmp(const void *p1, const void *p2)
|
|||||||
&& IPV4_ADDR_SAME(&attr1->originator_id,
|
&& IPV4_ADDR_SAME(&attr1->originator_id,
|
||||||
&attr2->originator_id)
|
&attr2->originator_id)
|
||||||
&& overlay_index_same(attr1, attr2)
|
&& overlay_index_same(attr1, attr2)
|
||||||
|
&& !memcmp(&attr1->esi, &attr2->esi, sizeof(esi_t))
|
||||||
&& attr1->nh_ifindex == attr2->nh_ifindex
|
&& attr1->nh_ifindex == attr2->nh_ifindex
|
||||||
&& attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
|
&& attr1->nh_lla_ifindex == attr2->nh_lla_ifindex
|
||||||
&& attr1->distance == attr2->distance
|
&& attr1->distance == attr2->distance
|
||||||
|
@ -253,6 +253,9 @@ struct attr {
|
|||||||
|
|
||||||
/* Link bandwidth value, if any. */
|
/* Link bandwidth value, if any. */
|
||||||
uint32_t link_bw;
|
uint32_t link_bw;
|
||||||
|
|
||||||
|
/* EVPN ES */
|
||||||
|
esi_t esi;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* rmap_change_flags definition */
|
/* rmap_change_flags definition */
|
||||||
|
@ -54,47 +54,27 @@ void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
|
|||||||
* format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ
|
* format accepted: AA:BB:CC:DD:EE:FF:GG:HH:II:JJ
|
||||||
* if id is null, check only is done
|
* if id is null, check only is done
|
||||||
*/
|
*/
|
||||||
bool str2esi(const char *str, struct eth_segment_id *id)
|
bool str2esi(const char *str, esi_t *id)
|
||||||
{
|
{
|
||||||
unsigned int a[ESI_LEN];
|
unsigned int a[ESI_BYTES];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!str)
|
if (!str)
|
||||||
return false;
|
return false;
|
||||||
if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x", a + 0, a + 1,
|
if (sscanf(str, "%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x:%2x", a + 0, a + 1,
|
||||||
a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9)
|
a + 2, a + 3, a + 4, a + 5, a + 6, a + 7, a + 8, a + 9)
|
||||||
!= ESI_LEN) {
|
!= ESI_BYTES) {
|
||||||
/* error in incoming str length */
|
/* error in incoming str length */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* valid mac address */
|
/* valid mac address */
|
||||||
if (!id)
|
if (!id)
|
||||||
return true;
|
return true;
|
||||||
for (i = 0; i < ESI_LEN; ++i)
|
for (i = 0; i < ESI_BYTES; ++i)
|
||||||
id->val[i] = a[i] & 0xff;
|
id->val[i] = a[i] & 0xff;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *esi2str(struct eth_segment_id *id)
|
|
||||||
{
|
|
||||||
char *ptr;
|
|
||||||
uint8_t *val;
|
|
||||||
|
|
||||||
if (!id)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
val = id->val;
|
|
||||||
ptr = XMALLOC(MTYPE_TMP,
|
|
||||||
(ESI_LEN * 2 + ESI_LEN - 1 + 1) * sizeof(char));
|
|
||||||
|
|
||||||
snprintf(ptr, (ESI_LEN * 2 + ESI_LEN - 1 + 1),
|
|
||||||
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", val[0],
|
|
||||||
val[1], val[2], val[3], val[4], val[5], val[6], val[7], val[8],
|
|
||||||
val[9]);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *ecom_mac2str(char *ecom_mac)
|
char *ecom_mac2str(char *ecom_mac)
|
||||||
{
|
{
|
||||||
char *en;
|
char *en;
|
||||||
@ -292,14 +272,3 @@ extern bool is_zero_gw_ip(const union gw_addr *gw_ip, const afi_t afi)
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern bool is_zero_esi(const struct eth_segment_id *esi)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ESI_LEN; i++)
|
|
||||||
if (esi->val[i])
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
@ -21,38 +21,20 @@
|
|||||||
#ifndef _QUAGGA_BGP_ATTR_EVPN_H
|
#ifndef _QUAGGA_BGP_ATTR_EVPN_H
|
||||||
#define _QUAGGA_BGP_ATTR_EVPN_H
|
#define _QUAGGA_BGP_ATTR_EVPN_H
|
||||||
|
|
||||||
/* value of first byte of ESI */
|
|
||||||
#define ESI_TYPE_ARBITRARY 0 /* */
|
|
||||||
#define ESI_TYPE_LACP 1 /* <> */
|
|
||||||
#define ESI_TYPE_BRIDGE 2 /* <Root bridge Mac-6B>:<Root Br Priority-2B>:00 */
|
|
||||||
#define ESI_TYPE_MAC 3 /* <Syst Mac Add-6B>:<Local Discriminator Value-3B> */
|
|
||||||
#define ESI_TYPE_ROUTER 4 /* <RouterId-4B>:<Local Discriminator Value-4B> */
|
|
||||||
#define ESI_TYPE_AS 5 /* <AS-4B>:<Local Discriminator Value-4B> */
|
|
||||||
|
|
||||||
#define MAX_ESI {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}
|
|
||||||
#define ESI_LEN 10
|
|
||||||
|
|
||||||
#define MAX_ET 0xffffffff
|
#define MAX_ET 0xffffffff
|
||||||
|
|
||||||
struct attr;
|
struct attr;
|
||||||
|
|
||||||
/* EVPN ESI */
|
|
||||||
struct eth_segment_id {
|
|
||||||
uint8_t val[ESI_LEN];
|
|
||||||
};
|
|
||||||
|
|
||||||
union gw_addr {
|
union gw_addr {
|
||||||
struct in_addr ipv4;
|
struct in_addr ipv4;
|
||||||
struct in6_addr ipv6;
|
struct in6_addr ipv6;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bgp_route_evpn {
|
struct bgp_route_evpn {
|
||||||
struct eth_segment_id eth_s_id;
|
|
||||||
union gw_addr gw_ip;
|
union gw_addr gw_ip;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern bool str2esi(const char *str, struct eth_segment_id *id);
|
extern bool str2esi(const char *str, esi_t *id);
|
||||||
extern char *esi2str(struct eth_segment_id *id);
|
|
||||||
extern char *ecom_mac2str(char *ecom_mac);
|
extern char *ecom_mac2str(char *ecom_mac);
|
||||||
|
|
||||||
extern void bgp_add_routermac_ecom(struct attr *attr,
|
extern void bgp_add_routermac_ecom(struct attr *attr,
|
||||||
@ -68,5 +50,4 @@ extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag);
|
|||||||
|
|
||||||
extern bool is_zero_gw_ip(const union gw_addr *gw_ip, afi_t afi);
|
extern bool is_zero_gw_ip(const union gw_addr *gw_ip, afi_t afi);
|
||||||
|
|
||||||
extern bool is_zero_esi(const struct eth_segment_id *esi);
|
|
||||||
#endif /* _QUAGGA_BGP_ATTR_EVPN_H */
|
#endif /* _QUAGGA_BGP_ATTR_EVPN_H */
|
||||||
|
@ -3537,7 +3537,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
|
|||||||
|
|
||||||
if (attr) {
|
if (attr) {
|
||||||
is_valid_update = true;
|
is_valid_update = true;
|
||||||
if (is_zero_mac(&attr->rmac) && is_zero_esi(&evpn.eth_s_id) &&
|
if (is_zero_mac(&attr->rmac) &&
|
||||||
is_zero_gw_ip(&evpn.gw_ip, gw_afi))
|
is_zero_gw_ip(&evpn.gw_ip, gw_afi))
|
||||||
is_valid_update = false;
|
is_valid_update = false;
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@
|
|||||||
#include "bgpd/bgp_encap_types.h"
|
#include "bgpd/bgp_encap_types.h"
|
||||||
#include "bgpd/bgp_encap_tlv.h"
|
#include "bgpd/bgp_encap_tlv.h"
|
||||||
#include "bgpd/bgp_evpn.h"
|
#include "bgpd/bgp_evpn.h"
|
||||||
|
#include "bgpd/bgp_evpn_mh.h"
|
||||||
#include "bgpd/bgp_evpn_vty.h"
|
#include "bgpd/bgp_evpn_vty.h"
|
||||||
#include "bgpd/bgp_flowspec.h"
|
#include "bgpd/bgp_flowspec.h"
|
||||||
#include "bgpd/bgp_flowspec_util.h"
|
#include "bgpd/bgp_flowspec_util.h"
|
||||||
@ -3172,19 +3173,10 @@ struct bgp_path_info *info_make(int type, int sub_type, unsigned short instance,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void overlay_index_update(struct attr *attr,
|
static void overlay_index_update(struct attr *attr,
|
||||||
struct eth_segment_id *eth_s_id,
|
|
||||||
union gw_addr *gw_ip)
|
union gw_addr *gw_ip)
|
||||||
{
|
{
|
||||||
if (!attr)
|
if (!attr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (eth_s_id == NULL) {
|
|
||||||
memset(&(attr->evpn_overlay.eth_s_id), 0,
|
|
||||||
sizeof(struct eth_segment_id));
|
|
||||||
} else {
|
|
||||||
memcpy(&(attr->evpn_overlay.eth_s_id), eth_s_id,
|
|
||||||
sizeof(struct eth_segment_id));
|
|
||||||
}
|
|
||||||
if (gw_ip == NULL) {
|
if (gw_ip == NULL) {
|
||||||
memset(&(attr->evpn_overlay.gw_ip), 0, sizeof(union gw_addr));
|
memset(&(attr->evpn_overlay.gw_ip), 0, sizeof(union gw_addr));
|
||||||
} else {
|
} else {
|
||||||
@ -3194,20 +3186,17 @@ static void overlay_index_update(struct attr *attr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool overlay_index_equal(afi_t afi, struct bgp_path_info *path,
|
static bool overlay_index_equal(afi_t afi, struct bgp_path_info *path,
|
||||||
struct eth_segment_id *eth_s_id,
|
|
||||||
union gw_addr *gw_ip)
|
union gw_addr *gw_ip)
|
||||||
{
|
{
|
||||||
struct eth_segment_id *path_eth_s_id, *path_eth_s_id_remote;
|
|
||||||
union gw_addr *path_gw_ip, *path_gw_ip_remote;
|
union gw_addr *path_gw_ip, *path_gw_ip_remote;
|
||||||
union {
|
union {
|
||||||
struct eth_segment_id esi;
|
esi_t esi;
|
||||||
union gw_addr ip;
|
union gw_addr ip;
|
||||||
} temp;
|
} temp;
|
||||||
|
|
||||||
if (afi != AFI_L2VPN)
|
if (afi != AFI_L2VPN)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
path_eth_s_id = &(path->attr->evpn_overlay.eth_s_id);
|
|
||||||
path_gw_ip = &(path->attr->evpn_overlay.gw_ip);
|
path_gw_ip = &(path->attr->evpn_overlay.gw_ip);
|
||||||
|
|
||||||
if (gw_ip == NULL) {
|
if (gw_ip == NULL) {
|
||||||
@ -3216,17 +3205,7 @@ static bool overlay_index_equal(afi_t afi, struct bgp_path_info *path,
|
|||||||
} else
|
} else
|
||||||
path_gw_ip_remote = gw_ip;
|
path_gw_ip_remote = gw_ip;
|
||||||
|
|
||||||
if (eth_s_id == NULL) {
|
return !!memcmp(path_gw_ip, path_gw_ip_remote, sizeof(union gw_addr));
|
||||||
memset(&temp, 0, sizeof(temp));
|
|
||||||
path_eth_s_id_remote = &temp.esi;
|
|
||||||
} else
|
|
||||||
path_eth_s_id_remote = eth_s_id;
|
|
||||||
|
|
||||||
if (!memcmp(path_gw_ip, path_gw_ip_remote, sizeof(union gw_addr)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return !memcmp(path_eth_s_id, path_eth_s_id_remote,
|
|
||||||
sizeof(struct eth_segment_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if received nexthop is valid or not. */
|
/* Check if received nexthop is valid or not. */
|
||||||
@ -3521,7 +3500,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
|
|||||||
num_labels * sizeof(mpls_label_t))
|
num_labels * sizeof(mpls_label_t))
|
||||||
== 0)
|
== 0)
|
||||||
&& (overlay_index_equal(
|
&& (overlay_index_equal(
|
||||||
afi, pi, evpn == NULL ? NULL : &evpn->eth_s_id,
|
afi, pi,
|
||||||
evpn == NULL ? NULL : &evpn->gw_ip))) {
|
evpn == NULL ? NULL : &evpn->gw_ip))) {
|
||||||
if (CHECK_FLAG(bgp->af_flags[afi][safi],
|
if (CHECK_FLAG(bgp->af_flags[afi][safi],
|
||||||
BGP_CONFIG_DAMPENING)
|
BGP_CONFIG_DAMPENING)
|
||||||
@ -3746,7 +3725,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
|
|||||||
/* Update Overlay Index */
|
/* Update Overlay Index */
|
||||||
if (afi == AFI_L2VPN) {
|
if (afi == AFI_L2VPN) {
|
||||||
overlay_index_update(
|
overlay_index_update(
|
||||||
pi->attr, evpn == NULL ? NULL : &evpn->eth_s_id,
|
pi->attr,
|
||||||
evpn == NULL ? NULL : &evpn->gw_ip);
|
evpn == NULL ? NULL : &evpn->gw_ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3912,7 +3891,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
|
|||||||
/* Update Overlay Index */
|
/* Update Overlay Index */
|
||||||
if (afi == AFI_L2VPN) {
|
if (afi == AFI_L2VPN) {
|
||||||
overlay_index_update(new->attr,
|
overlay_index_update(new->attr,
|
||||||
evpn == NULL ? NULL : &evpn->eth_s_id,
|
|
||||||
evpn == NULL ? NULL : &evpn->gw_ip);
|
evpn == NULL ? NULL : &evpn->gw_ip);
|
||||||
}
|
}
|
||||||
/* Nexthop reachability check. */
|
/* Nexthop reachability check. */
|
||||||
@ -5301,7 +5279,7 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p,
|
|||||||
else if (bgp_static->gatewayIp.family == AF_INET6)
|
else if (bgp_static->gatewayIp.family == AF_INET6)
|
||||||
memcpy(&(add.ipv6), &(bgp_static->gatewayIp.u.prefix6),
|
memcpy(&(add.ipv6), &(bgp_static->gatewayIp.u.prefix6),
|
||||||
sizeof(struct in6_addr));
|
sizeof(struct in6_addr));
|
||||||
overlay_index_update(&attr, bgp_static->eth_s_id, &add);
|
memcpy(&attr.esi, bgp_static->eth_s_id, sizeof(esi_t));
|
||||||
if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN) {
|
if (bgp_static->encap_tunneltype == BGP_ENCAP_TYPE_VXLAN) {
|
||||||
struct bgp_encap_type_vxlan bet;
|
struct bgp_encap_type_vxlan bet;
|
||||||
memset(&bet, 0, sizeof(struct bgp_encap_type_vxlan));
|
memset(&bet, 0, sizeof(struct bgp_encap_type_vxlan));
|
||||||
@ -5352,7 +5330,7 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p,
|
|||||||
if (pi) {
|
if (pi) {
|
||||||
memset(&add, 0, sizeof(union gw_addr));
|
memset(&add, 0, sizeof(union gw_addr));
|
||||||
if (attrhash_cmp(pi->attr, attr_new)
|
if (attrhash_cmp(pi->attr, attr_new)
|
||||||
&& overlay_index_equal(afi, pi, bgp_static->eth_s_id, &add)
|
&& overlay_index_equal(afi, pi, &add)
|
||||||
&& !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
|
&& !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
|
||||||
bgp_dest_unlock_node(dest);
|
bgp_dest_unlock_node(dest);
|
||||||
bgp_attr_unintern(&attr_new);
|
bgp_attr_unintern(&attr_new);
|
||||||
@ -5856,7 +5834,7 @@ int bgp_static_set_safi(afi_t afi, safi_t safi, struct vty *vty,
|
|||||||
if (esi) {
|
if (esi) {
|
||||||
bgp_static->eth_s_id =
|
bgp_static->eth_s_id =
|
||||||
XCALLOC(MTYPE_ATTR,
|
XCALLOC(MTYPE_ATTR,
|
||||||
sizeof(struct eth_segment_id));
|
sizeof(esi_t));
|
||||||
str2esi(esi, bgp_static->eth_s_id);
|
str2esi(esi, bgp_static->eth_s_id);
|
||||||
}
|
}
|
||||||
if (routermac) {
|
if (routermac) {
|
||||||
@ -8340,15 +8318,6 @@ void route_vty_out_overlay(struct vty *vty, const struct prefix *p,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *str = esi2str(&(attr->evpn_overlay.eth_s_id));
|
|
||||||
|
|
||||||
if (!json_path)
|
|
||||||
vty_out(vty, "%s", str);
|
|
||||||
else
|
|
||||||
json_object_string_add(json_overlay, "esi", str);
|
|
||||||
|
|
||||||
XFREE(MTYPE_TMP, str);
|
|
||||||
|
|
||||||
if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)p)) {
|
if (is_evpn_prefix_ipaddr_v4((struct prefix_evpn *)p)) {
|
||||||
inet_ntop(AF_INET, &(attr->evpn_overlay.gw_ip.ipv4), buf,
|
inet_ntop(AF_INET, &(attr->evpn_overlay.gw_ip.ipv4), buf,
|
||||||
BUFSIZ);
|
BUFSIZ);
|
||||||
@ -13316,6 +13285,7 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
|
|||||||
char buf[PREFIX_STRLEN * 2];
|
char buf[PREFIX_STRLEN * 2];
|
||||||
char buf2[SU_ADDRSTRLEN];
|
char buf2[SU_ADDRSTRLEN];
|
||||||
char rdbuf[RD_ADDRSTRLEN];
|
char rdbuf[RD_ADDRSTRLEN];
|
||||||
|
char esi_buf[ESI_BYTES];
|
||||||
|
|
||||||
/* Network configuration. */
|
/* Network configuration. */
|
||||||
for (pdest = bgp_table_top(bgp->route[afi][safi]); pdest;
|
for (pdest = bgp_table_top(bgp->route[afi][safi]); pdest;
|
||||||
@ -13331,13 +13301,13 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
char *macrouter = NULL;
|
char *macrouter = NULL;
|
||||||
char *esi = NULL;
|
|
||||||
|
|
||||||
if (bgp_static->router_mac)
|
if (bgp_static->router_mac)
|
||||||
macrouter = prefix_mac2str(
|
macrouter = prefix_mac2str(
|
||||||
bgp_static->router_mac, NULL, 0);
|
bgp_static->router_mac, NULL, 0);
|
||||||
if (bgp_static->eth_s_id)
|
if (bgp_static->eth_s_id)
|
||||||
esi = esi2str(bgp_static->eth_s_id);
|
esi_to_str(bgp_static->eth_s_id,
|
||||||
|
esi_buf, sizeof(esi_buf));
|
||||||
p = bgp_dest_get_prefix(dest);
|
p = bgp_dest_get_prefix(dest);
|
||||||
prd = (struct prefix_rd *)bgp_dest_get_prefix(pdest);
|
prd = (struct prefix_rd *)bgp_dest_get_prefix(pdest);
|
||||||
|
|
||||||
@ -13368,11 +13338,10 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
|
|||||||
" network %s rd %s ethtag %u label %u esi %s gwip %s routermac %s\n",
|
" network %s rd %s ethtag %u label %u esi %s gwip %s routermac %s\n",
|
||||||
buf, rdbuf,
|
buf, rdbuf,
|
||||||
p->u.prefix_evpn.prefix_addr.eth_tag,
|
p->u.prefix_evpn.prefix_addr.eth_tag,
|
||||||
decode_label(&bgp_static->label), esi, buf2,
|
decode_label(&bgp_static->label), esi_buf, buf2,
|
||||||
macrouter);
|
macrouter);
|
||||||
|
|
||||||
XFREE(MTYPE_TMP, macrouter);
|
XFREE(MTYPE_TMP, macrouter);
|
||||||
XFREE(MTYPE_TMP, esi);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,7 +303,7 @@ struct bgp_static {
|
|||||||
mpls_label_t label;
|
mpls_label_t label;
|
||||||
|
|
||||||
/* EVPN */
|
/* EVPN */
|
||||||
struct eth_segment_id *eth_s_id;
|
esi_t *eth_s_id;
|
||||||
struct ethaddr *router_mac;
|
struct ethaddr *router_mac;
|
||||||
uint16_t encap_tunneltype;
|
uint16_t encap_tunneltype;
|
||||||
struct prefix gatewayIp;
|
struct prefix gatewayIp;
|
||||||
|
Loading…
Reference in New Issue
Block a user