0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

Follow-up work on integration

Contains some patches from Jan Moskyto Matejka
This commit is contained in:
Ondrej Zajicek (work) 2015-12-21 17:17:21 +01:00
parent 23c212e7f1
commit 0bf95f99e6
17 changed files with 47 additions and 156 deletions

View File

@ -1095,11 +1095,11 @@ interpret(struct f_inst *what)
runtime( "Integer expected"); runtime( "Integer expected");
if (v1.type != T_IP) if (v1.type != T_IP)
runtime( "You can mask only IP addresses" ); runtime( "You can mask only IP addresses" );
{
ip_addr mask = ipa_mkmask(v2.val.i);
res.type = T_IP; res.type = T_IP;
res.val.ip = ipa_and(mask, v1.val.ip); res.val.ip = ipa_is_ip4(v1.val.ip) ?
} ipa_from_ip4(ip4_and(ipa_to_ip4(v1.val.ip), ip4_mkmask(v2.val.i))) :
ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i)));
break; break;
case 'E': /* Create empty attribute */ case 'E': /* Create empty attribute */

View File

@ -76,7 +76,7 @@ int same_tree(struct f_tree *t1, struct f_tree *t2);
void tree_format(struct f_tree *t, buffer *buf); void tree_format(struct f_tree *t, buffer *buf);
struct f_trie *f_new_trie(linpool *lp, uint node_size); struct f_trie *f_new_trie(linpool *lp, uint node_size);
void *trie_add_prefix(struct f_trie *t, net_addr *n, uint l, uint h); void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h);
int trie_match_net(struct f_trie *t, const net_addr *n); int trie_match_net(struct f_trie *t, const net_addr *n);
int trie_same(struct f_trie *t1, struct f_trie *t2); int trie_same(struct f_trie *t1, struct f_trie *t2);
void trie_format(struct f_trie *t, buffer *buf); void trie_format(struct f_trie *t, buffer *buf);

View File

@ -74,6 +74,19 @@
#include "conf/conf.h" #include "conf/conf.h"
#include "filter/filter.h" #include "filter/filter.h"
/*
* In the trie code, the prefix length is internally treated as for the whole
* ip_addr, regardless whether it contains an IPv4 or IPv6 address. Therefore,
* remaining definitions make sense.
*/
#define ipa_mkmask(x) ip6_mkmask(x)
#define ipa_masklen(x) ip6_masklen(&x)
#define ipa_pxlen(x,y) ip6_pxlen(x,y)
#define ipa_getbit(x,n) ip6_getbit(x,n)
/** /**
* f_new_trie - allocates and returns a new empty trie * f_new_trie - allocates and returns a new empty trie
* @lp: linear pool to allocate items from * @lp: linear pool to allocate items from
@ -123,7 +136,7 @@ attach_node(struct f_trie_node *parent, struct f_trie_node *child)
*/ */
void * void *
trie_add_prefix(struct f_trie *t, net_addr *net, uint l, uint h) trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h)
{ {
ip_addr px = net_prefix(net); ip_addr px = net_prefix(net);
uint plen = net_pxlen(net); uint plen = net_pxlen(net);

View File

@ -55,12 +55,6 @@ static inline int u64_cmp(u64 i1, u64 i2)
#define NULL ((void *) 0) #define NULL ((void *) 0)
#endif #endif
#ifndef IPV6
#define IP_VERSION 4
#else
#define IP_VERSION 6
#endif
/* Macros for gcc attributes */ /* Macros for gcc attributes */

101
lib/ip.h
View File

@ -77,8 +77,6 @@ typedef struct ip6_addr {
#define _I3(a) ((a).addr[3]) #define _I3(a) ((a).addr[3])
#ifdef IPV6
/* Structure ip_addr may contain both IPv4 and IPv6 addresses */ /* Structure ip_addr may contain both IPv4 and IPv6 addresses */
typedef ip6_addr ip_addr; typedef ip6_addr ip_addr;
#define IPA_NONE IP6_NONE #define IPA_NONE IP6_NONE
@ -93,24 +91,6 @@ typedef ip6_addr ip_addr;
#define ipa_is_ip4(a) ip6_is_v4mapped(a) #define ipa_is_ip4(a) ip6_is_v4mapped(a)
#else
/* Provisionary ip_addr definition same as ip4_addr */
typedef ip4_addr ip_addr;
#define IPA_NONE IP4_NONE
#define ipa_from_ip4(x) x
#define ipa_from_ip6(x) IPA_NONE
#define ipa_from_u32(x) ipa_from_ip4(ip4_from_u32(x))
#define ipa_to_ip4(x) x
#define ipa_to_ip6(x) IP6_NONE
#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x))
#define ipa_is_ip4(a) 1
#endif
/* /*
* Public constructors * Public constructors
@ -174,7 +154,6 @@ static inline ip6_addr ip6_not(ip6_addr a)
{ return _MI6(~_I0(a), ~_I1(a), ~_I2(a), ~_I3(a)); } { return _MI6(~_I0(a), ~_I1(a), ~_I2(a), ~_I3(a)); }
#ifdef IPV6
#define ipa_equal(x,y) ip6_equal(x,y) #define ipa_equal(x,y) ip6_equal(x,y)
#define ipa_zero(x) ip6_zero(x) #define ipa_zero(x) ip6_zero(x)
#define ipa_nonzero(x) ip6_nonzero(x) #define ipa_nonzero(x) ip6_nonzero(x)
@ -182,19 +161,8 @@ static inline ip6_addr ip6_not(ip6_addr a)
#define ipa_or(x,y) ip6_or(x,y) #define ipa_or(x,y) ip6_or(x,y)
#define ipa_xor(x,y) ip6_xor(x,y) #define ipa_xor(x,y) ip6_xor(x,y)
#define ipa_not(x) ip6_not(x) #define ipa_not(x) ip6_not(x)
#else
#define ipa_equal(x,y) ip4_equal(x,y)
#define ipa_zero(x) ip4_zero(x)
#define ipa_nonzero(x) ip4_nonzero(x)
#define ipa_and(x,y) ip4_and(x,y)
#define ipa_or(x,y) ip4_or(x,y)
#define ipa_xor(x,y) ip4_xor(x,y)
#define ipa_not(x) ip4_not(x)
#endif
#ifdef IPV6
/* /*
* A zero address is either a token for invalid/unused, or the prefix of default * A zero address is either a token for invalid/unused, or the prefix of default
* routes. These functions should be used in the second case, where both IPv4 * routes. These functions should be used in the second case, where both IPv4
@ -207,11 +175,6 @@ static inline int ipa_zero2(ip_addr a)
static inline int ipa_nonzero2(ip_addr a) static inline int ipa_nonzero2(ip_addr a)
{ return _I0(a) || _I1(a) || ((_I2(a) != 0) && (_I2(a) != 0xffff)) || _I3(a); } { return _I0(a) || _I1(a) || ((_I2(a) != 0) && (_I2(a) != 0xffff)) || _I3(a); }
#else
#define ipa_zero2(x) ip4_zero(x)
#define ipa_nonzero2(x) ip4_nonzero(x)
#endif
/* /*
* Hash and compare functions * Hash and compare functions
@ -254,16 +217,9 @@ static inline int ip4_compare(ip4_addr a, ip4_addr b)
int ip6_compare(ip6_addr a, ip6_addr b); int ip6_compare(ip6_addr a, ip6_addr b);
#ifdef IPV6
#define ipa_hash(x) ip6_hash(x) #define ipa_hash(x) ip6_hash(x)
#define ipa_hash32(x) ip6_hash32(x) #define ipa_hash32(x) ip6_hash32(x)
#define ipa_compare(x,y) ip6_compare(x,y) #define ipa_compare(x,y) ip6_compare(x,y)
#else
#define ipa_hash(x) ip4_hash(x)
#define ipa_hash32(x) ip4_hash32(x)
#define ipa_compare(x,y) ip4_compare(x,y)
#endif
/* /*
@ -294,14 +250,10 @@ static inline int ip6_is_link_local(ip6_addr a)
static inline int ip6_is_v4mapped(ip6_addr a) static inline int ip6_is_v4mapped(ip6_addr a)
{ return _I0(a) == 0 && _I1(a) == 0 && _I2(a) == 0xffff; } { return _I0(a) == 0 && _I1(a) == 0 && _I2(a) == 0xffff; }
#ifdef IPV6
#define ipa_classify(x) ip6_classify(&(x)) #define ipa_classify(x) ip6_classify(&(x))
#define ipa_is_link_local(x) ip6_is_link_local(x) #define ipa_is_link_local(x) ip6_is_link_local(x)
#else
#define ipa_classify(x) ip4_classify(x)
#define ipa_is_link_local(x) 0
#endif
/* XXXX remove */
static inline int ipa_classify_net(ip_addr a) static inline int ipa_classify_net(ip_addr a)
{ return ipa_zero2(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); } { return ipa_zero2(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); }
@ -365,25 +317,8 @@ static inline ip6_addr ip6_opposite_m2(ip6_addr a)
ip4_addr ip4_class_mask(ip4_addr ad); ip4_addr ip4_class_mask(ip4_addr ad);
#ifdef IPV6
#define ipa_mkmask(x) ip6_mkmask(x)
#define ipa_masklen(x) ip6_masklen(&x)
#define ipa_pxlen(x,y) ip6_pxlen(x,y)
#define ipa_getbit(x,n) ip6_getbit(x,n)
#define ipa_setbit(x,n) ip6_setbit(x,n)
#define ipa_clrbit(x,n) ip6_clrbit(x,n)
#define ipa_opposite_m1(x) ip6_opposite_m1(x) #define ipa_opposite_m1(x) ip6_opposite_m1(x)
#define ipa_opposite_m2(x) ip6_opposite_m2(x) #define ipa_opposite_m2(x) ip6_opposite_m2(x)
#else
#define ipa_mkmask(x) ip4_mkmask(x)
#define ipa_masklen(x) ip4_masklen(x)
#define ipa_pxlen(x,y) ip4_pxlen(x,y)
#define ipa_getbit(x,n) ip4_getbit(x,n)
#define ipa_setbit(x,n) ip4_setbit(x,n)
#define ipa_clrbit(x,n) ip4_clrbit(x,n)
#define ipa_opposite_m1(x) ip4_opposite_m1(x)
#define ipa_opposite_m2(x) ip4_opposite_m2(x)
#endif
/* /*
@ -402,14 +337,6 @@ static inline ip6_addr ip6_hton(ip6_addr a)
static inline ip6_addr ip6_ntoh(ip6_addr a) static inline ip6_addr ip6_ntoh(ip6_addr a)
{ return _MI6(ntohl(_I0(a)), ntohl(_I1(a)), ntohl(_I2(a)), ntohl(_I3(a))); } { return _MI6(ntohl(_I0(a)), ntohl(_I1(a)), ntohl(_I2(a)), ntohl(_I3(a))); }
#ifdef IPV6
#define ipa_hton(x) x = ip6_hton(x)
#define ipa_ntoh(x) x = ip6_ntoh(x)
#else
#define ipa_hton(x) x = ip4_hton(x)
#define ipa_ntoh(x) x = ip4_ntoh(x)
#endif
/* /*
* Unaligned data access (in network order) * Unaligned data access (in network order)
@ -440,15 +367,6 @@ static inline void * put_ip6(void *buf, ip6_addr a)
return buf+16; return buf+16;
} }
// XXXX these functions must be redesigned or removed
#ifdef IPV6
#define get_ipa(x) get_ip6(x)
#define put_ipa(x,y) put_ip6(x,y)
#else
#define get_ipa(x) get_ip4(x)
#define put_ipa(x,y) put_ip4(x,y)
#endif
/* /*
* Binary/text form conversions * Binary/text form conversions
@ -466,28 +384,11 @@ static inline char * ip6_ntox(ip6_addr a, char *b)
int ip4_pton(const char *a, ip4_addr *o); int ip4_pton(const char *a, ip4_addr *o);
int ip6_pton(const char *a, ip6_addr *o); int ip6_pton(const char *a, ip6_addr *o);
// XXXX these functions must be redesigned or removed
#ifdef IPV6
#define ipa_ntop(x,y) ip6_ntop(x,y)
#define ipa_ntox(x,y) ip6_ntox(x,y)
#define ipa_pton(x,y) ip6_pton(x,y)
#else
#define ipa_ntop(x,y) ip4_ntop(x,y)
#define ipa_ntox(x,y) ip4_ntox(x,y)
#define ipa_pton(x,y) ip4_pton(x,y)
#endif
/* /*
* Miscellaneous * Miscellaneous
*/ */
// XXXX review this
#define ip_is_prefix(a,l) (!ipa_nonzero(ipa_and(a, ipa_not(ipa_mkmask(l)))))
#define ipa_in_net(x,n,p) (ipa_zero(ipa_and(ipa_xor((n),(x)),ipa_mkmask(p))))
#define net_in_net(n1,l1,n2,l2) (((l1) >= (l2)) && (ipa_zero(ipa_and(ipa_xor((n1),(n2)),ipa_mkmask(l2)))))
char *ip_scope_text(uint); char *ip_scope_text(uint);
#endif #endif

View File

@ -136,33 +136,36 @@ net_classify(const net_addr *N)
return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix); return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix);
} }
return 0; return IADDR_INVALID;
} }
int int
ipa_in_netX(const ip_addr A, const net_addr *N) ipa_in_netX(const ip_addr a, const net_addr *n)
{ {
switch (N->type) switch (n->type)
{ {
case NET_IP4: case NET_IP4:
case NET_VPN4: case NET_VPN4:
if (!ipa_is_ip4(A)) return 0; if (!ipa_is_ip4(a)) return 0;
break; return ip4_zero(ip4_and(ip4_xor(ipa_to_ip4(a), net4_prefix(n)),
ip4_mkmask(net4_pxlen(n))));
case NET_IP6: case NET_IP6:
case NET_VPN6: case NET_VPN6:
if (ipa_is_ip4(A)) return 0; if (ipa_is_ip4(a)) return 0;
break; return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)),
} ip6_mkmask(net6_pxlen(n))));
return ipa_zero(ipa_and(ipa_xor(A, net_prefix(N)), ipa_mkmask(net_pxlen(N)))); default:
return 0;
}
} }
int int
net_in_netX(const net_addr *A, const net_addr *N) net_in_netX(const net_addr *a, const net_addr *n)
{ {
if (A->type != N->type) if (a->type != n->type)
return 0; return 0;
return (net_pxlen(N) <= net_pxlen(A)) && ipa_in_netX(net_prefix(A), N); return (net_pxlen(n) <= net_pxlen(a)) && ipa_in_netX(net_prefix(a), n);
} }

View File

@ -55,7 +55,7 @@ CF_DECLS
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS) CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(IPV4, IPVX, VPN4, VPN6) CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED) CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE) /* ,ROA */ CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE) /* ,ROA */
@ -134,7 +134,7 @@ CF_ADDTO(conf, table)
table_type: table_type:
/* empty */ { $$ = NET_IP4; } /* empty */ { $$ = NET_IP4; }
| IPV4 { $$ = NET_IP4; } | IPV4 { $$ = NET_IP4; }
| IPVX { $$ = NET_IP6; } /* XXXX */ | IPV6 { $$ = NET_IP6; }
| VPN4 { $$ = NET_VPN4; } | VPN4 { $$ = NET_VPN4; }
| VPN6 { $$ = NET_VPN6; } | VPN6 { $$ = NET_VPN6; }
; ;

View File

@ -316,7 +316,6 @@ ospf_iface_item:
| TTL SECURITY bool { OSPF_PATT->ttl_security = $3; } | TTL SECURITY bool { OSPF_PATT->ttl_security = $3; }
| TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; } | TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
| BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); } | BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
| SECONDARY bool { OSPF_PATT->bsd_secondary = $2; }
| password_list { ospf_check_auth(); } | password_list { ospf_check_auth(); }
; ;

View File

@ -525,15 +525,6 @@ ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
if (addr->iface->flags & IF_LOOPBACK) if (addr->iface->flags & IF_LOOPBACK)
return 1; return 1;
/*
* For compatibility reasons on BSD systems, we force OSPF
* interfaces with non-primary IP prefixes to be stub.
*/
#if defined(OSPFv2) && !defined(CONFIG_MC_PROPER_SRC)
if (!ip->bsd_secondary && !(addr->flags & IA_PRIMARY))
return 1;
#endif
return ip->stub; return ip->stub;
} }

View File

@ -185,7 +185,6 @@ struct ospf_iface_patt
u8 ptp_netmask; /* bool + 2 for unspecified */ u8 ptp_netmask; /* bool + 2 for unspecified */
u8 ttl_security; /* bool + 2 for TX only */ u8 ttl_security; /* bool + 2 for TX only */
u8 bfd; u8 bfd;
u8 bsd_secondary;
list *passwords; list *passwords;
}; };

View File

@ -71,6 +71,7 @@
#define KRT_MAX_TABLES 1 #define KRT_MAX_TABLES 1
#endif #endif
#define IPV6 1
/* Dynamic max number of tables */ /* Dynamic max number of tables */

View File

@ -9,9 +9,6 @@
/* BIRD version */ /* BIRD version */
#define BIRD_VERSION "1.5.0" #define BIRD_VERSION "1.5.0"
/* XXXX Temporary */
#define IPV6 1
/* Include parameters determined by configure script */ /* Include parameters determined by configure script */
#include "sysdep/autoconf.h" #include "sysdep/autoconf.h"

View File

@ -1169,7 +1169,8 @@ nl_parse_route(struct nlmsghdr *h, int scan)
ra.gw = rta_get_ipa(a[RTA_GATEWAY]); ra.gw = rta_get_ipa(a[RTA_GATEWAY]);
/* Silently skip strange 6to4 routes */ /* Silently skip strange 6to4 routes */
if ((i->rtm_family == AF_INET6) && ipa_in_net(ra.gw, IPA_NONE, 96)) const net_addr_ip6 sit = NET_ADDR_IP6(IP6_NONE, 96);
if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra.gw, (net_addr *) &sit))
return; return;
neighbor *nbr; neighbor *nbr;

View File

@ -69,8 +69,7 @@ kif_item:
} }
| PRIMARY opttext net_or_ipa { | PRIMARY opttext net_or_ipa {
struct kif_primary_item *kpi = cfg_alloc(sizeof (struct kif_primary_item)); struct kif_primary_item *kpi = cfg_alloc(sizeof (struct kif_primary_item));
kpi->prefix = IPA_NONE; /* XXXX */ kpi->addr = $3.n;
kpi->pxlen = 0; /* XXXX */
add_tail(&THIS_KIF->primary, &kpi->n); add_tail(&THIS_KIF->primary, &kpi->n);
} }
; ;

View File

@ -131,14 +131,14 @@ prefer_addr(struct ifa *a, struct ifa *b)
} }
static inline struct ifa * static inline struct ifa *
find_preferred_ifa(struct iface *i, ip_addr prefix, ip_addr mask) find_preferred_ifa(struct iface *i, const net_addr *n)
{ {
struct ifa *a, *b = NULL; struct ifa *a, *b = NULL;
WALK_LIST(a, i->addrs) WALK_LIST(a, i->addrs)
{ {
if (!(a->flags & IA_SECONDARY) && if (!(a->flags & IA_SECONDARY) &&
ipa_equal(ipa_and(a->ip, mask), prefix) && (!n || ipa_in_netX(a->ip, n)) &&
(!b || prefer_addr(a, b))) (!b || prefer_addr(a, b)))
b = a; b = a;
} }
@ -156,14 +156,14 @@ kif_choose_primary(struct iface *i)
WALK_LIST(it, cf->primary) WALK_LIST(it, cf->primary)
{ {
if (!it->pattern || patmatch(it->pattern, i->name)) if (!it->pattern || patmatch(it->pattern, i->name))
if (a = find_preferred_ifa(i, it->prefix, ipa_mkmask(it->pxlen))) if (a = find_preferred_ifa(i, &it->addr))
return a; return a;
} }
if (a = kif_get_primary_ip(i)) if (a = kif_get_primary_ip(i))
return a; return a;
return find_preferred_ifa(i, IPA_NONE, IPA_NONE); return find_preferred_ifa(i, NULL);
} }

View File

@ -97,8 +97,7 @@ extern struct protocol proto_unix_iface;
struct kif_primary_item { struct kif_primary_item {
node n; node n;
byte *pattern; byte *pattern;
ip_addr prefix; net_addr addr;
int pxlen;
}; };
struct kif_config { struct kif_config {

View File

@ -80,14 +80,8 @@ static inline ip_addr ipa_from_sa(sockaddr *sa)
static inline struct in_addr ipa_to_in4(ip_addr a) static inline struct in_addr ipa_to_in4(ip_addr a)
{ return (struct in_addr) { htonl(ipa_to_u32(a)) }; } { return (struct in_addr) { htonl(ipa_to_u32(a)) }; }
#ifdef IPV6
static inline struct in6_addr ipa_to_in6(ip_addr a) static inline struct in6_addr ipa_to_in6(ip_addr a)
{ return (struct in6_addr) { .s6_addr32 = { htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a)) } }; } { return (struct in6_addr) { .s6_addr32 = { htonl(_I0(a)), htonl(_I1(a)), htonl(_I2(a)), htonl(_I3(a)) } }; }
#else
/* Temporary dummy */
static inline struct in6_addr ipa_to_in6(ip_addr a)
{ return (struct in6_addr) { .s6_addr32 = { 0, 0, 0, 0 } }; }
#endif
void sockaddr_fill(sockaddr *sa, int af, ip_addr a, struct iface *ifa, uint port); void sockaddr_fill(sockaddr *sa, int af, ip_addr a, struct iface *ifa, uint port);
int sockaddr_read(sockaddr *sa, int af, ip_addr *a, struct iface **ifa, uint *port); int sockaddr_read(sockaddr *sa, int af, ip_addr *a, struct iface **ifa, uint *port);