OSPF: Support of address families in OSPFv3

OSPFv3-AF can handle multiple topologies of diferent address families
(IPv4, IPv6, both unicast and multicast) using separate instances
distinguished by instance ID ranges.
This commit is contained in:
Ondrej Zajicek (work) 2017-10-09 01:16:29 +02:00
parent 15a4421f9c
commit d3f4f92b0e
10 changed files with 262 additions and 136 deletions

View file

@ -78,18 +78,66 @@ static void
ospf_proto_finish(void)
{
struct ospf_config *cf = OSPF_CFG;
if (EMPTY_LIST(cf->area_list))
cf_error( "No configured areas in OSPF");
struct ospf_area_config *ac;
struct ospf_iface_patt *ic;
/* Define default channel */
if (EMPTY_LIST(this_proto->channels))
{
this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
channel_config_new(NULL, this_proto->net_type, this_proto);
}
/* Propagate global instance ID to interfaces */
if (cf->instance_id_set)
{
WALK_LIST(ac, cf->area_list)
WALK_LIST(ic, ac->patt_list)
if (!ic->instance_id_set)
{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
WALK_LIST(ic, cf->vlink_list)
if (!ic->instance_id_set)
{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
}
if (ospf_cfg_is_v3())
{
uint ipv4 = (this_proto->net_type == NET_IP4);
uint base = (ipv4 ? 64 : 0) + (cf->af_mc ? 32 : 0);
/* RFC 5838 - OSPFv3-AF */
if (cf->af_ext)
{
/* RFC 5838 2.1 - instance IDs based on AFs */
WALK_LIST(ac, cf->area_list)
WALK_LIST(ic, ac->patt_list)
{
if (!ic->instance_id_set)
ic->instance_id = base;
else if (ic->instance_id >= 128)
log(L_WARN "Instance ID %d from unassigned/private range", ic->instance_id);
else if ((ic->instance_id < base) || (ic->instance_id >= (base + 32)))
cf_error("Instance ID %d invalid for given channel type", ic->instance_id);
}
/* RFC 5838 2.8 - vlinks limited to IPv6 unicast */
if ((ipv4 || cf->af_mc) && !EMPTY_LIST(cf->vlink_list))
cf_error("Vlinks not supported in AFs other than IPv6 unicast");
}
else
{
if (ipv4 || cf->af_mc)
cf_error("Different channel type");
}
}
if (EMPTY_LIST(cf->area_list))
cf_error("No configured areas in OSPF");
int areano = 0;
int backbone = 0;
int nssa = 0;
struct ospf_area_config *ac;
WALK_LIST(ac, cf->area_list)
{
areano++;
@ -148,10 +196,11 @@ CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION)
CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION, MULTICAST)
%type <ld> lsadb_args
%type <i> ospf_variant nbma_eligible
%type <i> ospf_variant ospf_af_mc nbma_eligible
%type <cc> ospf_channel_start ospf_channel
CF_GRAMMAR
@ -166,12 +215,13 @@ ospf_variant:
ospf_proto_start: proto_start ospf_variant
{
this_proto = proto_config_new(&proto_ospf, $1);
this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
this_proto->net_type = $2 ? NET_IP4 : 0;
init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list);
OSPF_CFG->tick = OSPF_DEFAULT_TICK;
OSPF_CFG->ospf2 = $2;
OSPF_CFG->af_ext = !$2;
};
ospf_proto:
@ -179,16 +229,33 @@ ospf_proto:
| ospf_proto ospf_proto_item ';'
;
ospf_af_mc:
{ $$ = 0; }
| MULTICAST { $$ = 1; }
;
/* We redefine proto_channel to add multicast flag */
ospf_channel_start: net_type ospf_af_mc
{
$$ = this_channel = channel_config_new(NULL, $1, this_proto);
/* Save the multicast flag */
if (this_channel == proto_cf_main_channel(this_proto))
OSPF_CFG->af_mc = $2;
};
ospf_channel: ospf_channel_start channel_opt_list channel_end;
ospf_proto_item:
proto_item
| proto_channel
| ospf_channel { this_proto->net_type = $1->net_type; }
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }
| MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; }
| TICK expr { OSPF_CFG->tick = $2; if($2 <= 0) cf_error("Tick must be greater than zero"); }
| INSTANCE ID expr { OSPF_CFG->instance_id = $3; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); }
| INSTANCE ID expr { OSPF_CFG->instance_id = $3; OSPF_CFG->instance_id_set = 1; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); }
| ospf_area
;
@ -293,7 +360,6 @@ ospf_vlink_start: VIRTUAL LINK idval
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->type = OSPF_IT_VLINK;
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
init_list(&OSPF_PATT->nbma_list);
reset_passwords();
}
@ -393,7 +459,6 @@ ospf_iface_start:
OSPF_PATT->priority = PRIORITY_D;
OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->type = OSPF_IT_UNDEF;
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
init_list(&OSPF_PATT->nbma_list);
OSPF_PATT->ptp_netmask = 2; /* not specified */
OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
@ -404,7 +469,7 @@ ospf_iface_start:
ospf_instance_id:
/* empty */
| INSTANCE expr { OSPF_PATT->instance_id = $2; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); }
| INSTANCE expr { OSPF_PATT->instance_id = $2; OSPF_PATT->instance_id_set = 1; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); }
;
ospf_iface_patt_list:

View file

@ -356,7 +356,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
if ((rcv_imms == DBDES_IMMS) &&
if (((rcv_imms & DBDES_IMMS) == DBDES_IMMS) &&
(n->rid > p->router_id) &&
(plen == ospf_dbdes_hdrlen(p)))
{

View file

@ -32,10 +32,7 @@ struct ospf_hello3_packet
struct ospf_packet hdr;
u32 iface_id;
u8 priority;
u8 options3;
u8 options2;
u8 options;
u32 options;
u16 helloint;
u16 deadint;
u32 dr;
@ -91,10 +88,7 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
struct ospf_hello3_packet *ps = (void *) pkt;
ps->iface_id = htonl(ifa->iface_id);
ps->priority = ifa->priority;
ps->options3 = ifa->oa->options >> 16;
ps->options2 = ifa->oa->options >> 8;
ps->options = ifa->oa->options;
ps->options = ntohl(ifa->oa->options | (ifa->priority << 24));
ps->helloint = ntohs(ifa->helloint);
ps->deadint = htons(ifa->deadint);
ps->dr = htonl(ifa->drid);
@ -190,7 +184,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_proto *p = ifa->oa->po;
const char *err_dsc = NULL;
u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr;
u8 rcv_options, rcv_priority;
uint rcv_options, rcv_priority;
uint loc_options = ifa->oa->options;
u32 *neighbors;
u32 neigh_count;
uint plen, i, err_val = 0;
@ -245,8 +240,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
rcv_deadint = ntohs(ps->deadint);
rcv_dr = ntohl(ps->dr);
rcv_bdr = ntohl(ps->bdr);
rcv_options = ps->options;
rcv_priority = ps->priority;
rcv_options = ntohl(ps->options) & 0x00FFFFFF;
rcv_priority = ntohl(ps->options) >> 24;
neighbors = ps->neighbors;
neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32);
@ -259,9 +254,13 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
DROP("dead interval mismatch", rcv_deadint);
/* Check whether bits E, N match */
if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N))
if ((rcv_options ^ loc_options) & (OPT_E | OPT_N))
DROP("area type mismatch", rcv_options);
/* RFC 5838 2.4 - AF-bit check unless on IPv6 unicast */
if ((loc_options & OPT_AF) && !(loc_options & OPT_V6) && !(rcv_options & OPT_AF))
DROP("AF-bit mismatch", rcv_options);
/* Check consistency of existing neighbor entry */
if (n)
{

View file

@ -1113,9 +1113,6 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
{
struct ospf_proto *p = (struct ospf_proto *) P;
if (a->prefix.type != NET_IP6)
return;
if (a->flags & IA_SECONDARY)
return;
@ -1126,6 +1123,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
other addresses are used for link-LSA. */
if (a->scope == SCOPE_LINK)
{
if (a->prefix.type != NET_IP6)
return;
if (flags & IF_CHANGE_UP)
{
struct ospf_mip_walk s = { .iface = a->iface };
@ -1143,6 +1143,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
}
else
{
if (a->prefix.type != ospf_get_af(p))
return;
struct ospf_iface *ifa;
WALK_LIST(ifa, p->iface_list)
if (ifa->iface == a->iface)

View file

@ -280,7 +280,7 @@ lsa_walk_rt(struct ospf_lsa_rt_walk *rt)
void
lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopts, u32 *metric)
lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric)
{
if (ospf2)
{
@ -292,7 +292,7 @@ lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopt
else
{
struct ospf_lsa_sum3_net *ls = en->lsa_body;
ospf_get_ipv6_prefix(ls->prefix, net, pxopts, NULL);
ospf3_get_prefix(ls->prefix, af, net, pxopts, NULL);
*metric = ls->metric & LSA_METRIC_MASK;
}
}
@ -317,7 +317,7 @@ lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u
}
void
lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt)
lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt)
{
if (ospf2)
{
@ -338,13 +338,13 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *r
else
{
struct ospf_lsa_ext3 *ext = en->lsa_body;
u32 *buf = ospf_get_ipv6_prefix(ext->rest, &rt->net, &rt->pxopts, NULL);
u32 *buf = ospf3_get_prefix(ext->rest, af, &rt->net, &rt->pxopts, NULL);
rt->metric = ext->metric & LSA_METRIC_MASK;
rt->ebit = ext->metric & LSA_EXT3_EBIT;
rt->fbit = ext->metric & LSA_EXT3_FBIT;
if (rt->fbit)
buf = ospf_get_ipv6_addr(buf, &rt->fwaddr);
buf = ospf3_get_addr(buf, af, &rt->fwaddr);
else
rt->fwaddr = IPA_NONE;

View file

@ -55,9 +55,9 @@ u16 lsa_verify_checksum(const void *lsa_n, int lsa_len);
int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2);
void lsa_walk_rt_init(struct ospf_proto *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt);
int lsa_walk_rt(struct ospf_lsa_rt_walk *rt);
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopts, u32 *metric);
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric);
void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options);
void lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt);
void lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt);
int lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body);
#endif /* _BIRD_OSPF_LSALIB_H_ */

View file

@ -92,8 +92,10 @@
* - RFC 2328 - main OSPFv2 standard
* - RFC 5340 - main OSPFv3 standard
* - RFC 3101 - OSPFv2 NSSA areas
* - RFC 6549 - OSPFv2 multi-instance extensions
* - RFC 6987 - OSPF stub router advertisement
* - RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication
* - RFC 5838 - OSPFv3 Support of Address Families
* - RFC 6549 - OSPFv2 Multi-Instance Extensions
* - RFC 6987 - OSPF Stub Router Advertisement
*/
#include <stdlib.h>
@ -115,9 +117,9 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
struct area_net_config *anc;
struct area_net *an;
fib_init(&oa->net_fib, p->p.pool, ospf_is_v2(p) ? NET_IP4 : NET_IP6,
fib_init(&oa->net_fib, p->p.pool, ospf_get_af(p),
sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
fib_init(&oa->enet_fib, p->p.pool, ospf_is_v2(p) ? NET_IP4 : NET_IP6,
fib_init(&oa->enet_fib, p->p.pool, ospf_get_af(p),
sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
WALK_LIST(anc, ac->net_list)
@ -134,6 +136,16 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
}
}
static inline uint
ospf_opts(struct ospf_proto *p)
{
if (ospf_is_v2(p))
return 0;
return ((ospf_is_ip6(p) && !p->af_mc) ? OPT_V6 : 0) |
(!p->stub_router ? OPT_R : 0) | (p->af_ext ? OPT_AF : 0);
}
static void
ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
{
@ -155,10 +167,7 @@ ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
if (oa->areaid == 0)
p->backbone = oa;
if (ospf_is_v2(p))
oa->options = ac->type;
else
oa->options = ac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
oa->options = ac->type | ospf_opts(p);
ospf_notify_rt_lsa(oa);
}
@ -224,6 +233,8 @@ ospf_start(struct proto *P)
p->router_id = proto_get_router_id(P->cf);
p->ospf2 = c->ospf2;
p->af_ext = c->af_ext;
p->af_mc = c->af_mc;
p->rfc1583 = c->rfc1583;
p->stub_router = c->stub_router;
p->merge_external = c->merge_external;
@ -238,8 +249,7 @@ ospf_start(struct proto *P)
p->nhpool = lp_new(P->pool, 12*sizeof(struct nexthop));
init_list(&(p->iface_list));
init_list(&(p->area_list));
fib_init(&p->rtf, P->pool, p->ospf2 ? NET_IP4 : NET_IP6,
sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
fib_init(&p->rtf, P->pool, ospf_get_af(p), sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
if (ospf_is_v3(p))
idm_init(&p->idm, P->pool, 16);
p->areano = 0;
@ -601,11 +611,7 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
struct ospf_iface *ifa;
oa->ac = nac;
if (ospf_is_v2(p))
oa->options = nac->type;
else
oa->options = nac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
oa->options = nac->type | ospf_opts(p);
if (nac->type != oac->type)
{
@ -659,6 +665,9 @@ ospf_reconfigure(struct proto *P, struct proto_config *CF)
if (old->abr != new->abr)
return 0;
if ((p->af_ext != new->af_ext) || (p->af_mc != new->af_mc))
return 0;
if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
return 0;
@ -1073,13 +1082,13 @@ show_lsa_network(struct top_hash_entry *he, int ospf2)
}
static inline void
show_lsa_sum_net(struct top_hash_entry *he, int ospf2)
show_lsa_sum_net(struct top_hash_entry *he, int ospf2, int af)
{
net_addr net;
u8 pxopts;
u32 metric;
lsa_parse_sum_net(he, ospf2, &net, &pxopts, &metric);
lsa_parse_sum_net(he, ospf2, af, &net, &pxopts, &metric);
cli_msg(-1016, "\t\txnetwork %N metric %u", &net, metric);
}
@ -1096,7 +1105,7 @@ show_lsa_sum_rt(struct top_hash_entry *he, int ospf2)
static inline void
show_lsa_external(struct top_hash_entry *he, int ospf2)
show_lsa_external(struct top_hash_entry *he, int ospf2, int af)
{
struct ospf_lsa_ext_local rt;
char str_via[IPA_MAX_TEXT_LENGTH + 8] = "";
@ -1105,7 +1114,7 @@ show_lsa_external(struct top_hash_entry *he, int ospf2)
if (he->lsa_type == LSA_T_EXT)
he->domain = 0; /* Unmark the LSA */
lsa_parse_ext(he, ospf2, &rt);
lsa_parse_ext(he, ospf2, af, &rt);
if (rt.fbit)
bsprintf(str_via, " via %I", rt.fwaddr);
@ -1119,7 +1128,7 @@ show_lsa_external(struct top_hash_entry *he, int ospf2)
}
static inline void
show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode, int af)
{
struct ospf_lsa_prefix *px = he->lsa_body;
u32 *buf;
@ -1142,7 +1151,7 @@ show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
u8 pxopts;
u16 metric;
buf = ospf_get_ipv6_prefix(buf, &net, &pxopts, &metric);
buf = ospf3_get_prefix(buf, af, &net, &pxopts, &metric);
if (px->ref_type == LSA_T_RT)
cli_msg(-1016, "\t\tstubnet %N metric %u", &net, metric);
@ -1156,6 +1165,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
{
struct ospf_proto *p = (struct ospf_proto *) P;
int ospf2 = ospf_is_v2(p);
int af = ospf_get_af(p);
uint i, ix, j1, jx;
u32 last_area = 0xFFFFFFFF;
@ -1276,7 +1286,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
case LSA_T_SUM_NET:
if (cnode->lsa_type == LSA_T_RT)
show_lsa_sum_net(he, ospf2);
show_lsa_sum_net(he, ospf2, af);
break;
case LSA_T_SUM_RT:
@ -1286,11 +1296,11 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
case LSA_T_EXT:
case LSA_T_NSSA:
show_lsa_external(he, ospf2);
show_lsa_external(he, ospf2, af);
break;
case LSA_T_PREFIX:
show_lsa_prefix(he, cnode);
show_lsa_prefix(he, cnode, af);
break;
}
@ -1304,7 +1314,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
ix++;
while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt))
show_lsa_external(hex[ix++], ospf2);
show_lsa_external(hex[ix++], ospf2, af);
cnode = NULL;
}
@ -1338,7 +1348,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
last_rt = he->lsa.rt;
}
show_lsa_external(he, ospf2);
show_lsa_external(he, ospf2, af);
}
}

View file

@ -84,10 +84,13 @@ struct ospf_config
struct proto_config c;
uint tick;
u8 ospf2;
u8 af_ext;
u8 af_mc;
u8 rfc1583;
u8 stub_router;
u8 merge_external;
u8 instance_id;
u8 instance_id_set;
u8 abr;
u8 asbr;
int ecmp;
@ -168,9 +171,9 @@ struct ospf_iface_patt
int tx_priority;
u16 tx_length;
u16 rx_buffer;
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
u8 instance_id;
u8 instance_id_set;
u8 autype; /* OSPF_AUTH_*, not really used in OSPFv3 */
u8 strictnbma;
u8 check_link;
@ -211,12 +214,14 @@ struct ospf_proto
int padj; /* Number of neighbors in Exchange or Loading state */
struct fib rtf; /* Routing table */
struct idm idm; /* OSPFv3 LSA ID map */
byte ospf2; /* OSPF v2 or v3 */
byte rfc1583; /* RFC1583 compatibility */
byte stub_router; /* Do not forward transit traffic */
byte merge_external; /* Should i merge external routes? */
byte asbr; /* May i originate any ext/NSSA lsa? */
byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
u8 ospf2; /* OSPF v2 or v3 */
u8 af_ext; /* OSPFv3-AF extension */
u8 af_mc; /* OSPFv3-AF multicast */
u8 rfc1583; /* RFC1583 compatibility */
u8 stub_router; /* Do not forward transit traffic */
u8 merge_external; /* Should i merge external routes? */
u8 asbr; /* May i originate any ext/NSSA lsa? */
u8 ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
struct ospf_area *backbone; /* If exists */
event *flood_event; /* Event for flooding LS updates */
void *lsab; /* LSA buffer used when originating router LSAs */
@ -449,14 +454,15 @@ struct ospf_neighbor
/* Generic option flags */
#define OPT_V6 0x01 /* OSPFv3, LSA relevant for IPv6 routing calculation */
#define OPT_E 0x02 /* Related to AS-external LSAs */
#define OPT_MC 0x04 /* Related to MOSPF, not used and obsolete */
#define OPT_N 0x08 /* Related to NSSA */
#define OPT_P 0x08 /* OSPFv2, flags P and N share position, see NSSA RFC */
#define OPT_EA 0x10 /* OSPFv2, external attributes, not used and obsolete */
#define OPT_R 0x10 /* OSPFv3, originator is active router */
#define OPT_DC 0x20 /* Related to demand circuits, not used */
#define OPT_V6 0x0001 /* OSPFv3, LSA relevant for IPv6 routing calculation */
#define OPT_E 0x0002 /* Related to AS-external LSAs */
#define OPT_MC 0x0004 /* Related to MOSPF, not used and obsolete */
#define OPT_N 0x0008 /* Related to NSSA */
#define OPT_P 0x0008 /* OSPFv2, flags P and N share position, see NSSA RFC */
#define OPT_EA 0x0010 /* OSPFv2, external attributes, not used and obsolete */
#define OPT_R 0x0010 /* OSPFv3, originator is active router */
#define OPT_DC 0x0020 /* Related to demand circuits, not used */
#define OPT_AF 0x0100 /* OSPFv3 Address Families (RFC 5838) */
/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
#define OPT_RT_B (0x01 << 24)
@ -718,74 +724,96 @@ lsa_net_count(struct ospf_lsa_header *lsa)
#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4)
#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
/* FIXME: these functions should be significantly redesigned w.r.t. integration,
also should be named as ospf3_* instead of *_ipv6_* */
static inline int
ospf_valid_prefix(net_addr *n)
{
/* In OSPFv2, prefix is stored as netmask; ip4_masklen() returns 255 for invalid one */
return n->pxlen <= IP6_MAX_PREFIX_LENGTH;
/*
* In OSPFv2, prefix is stored as netmask; ip4_masklen() returns 255 for
* invalid one. But OSPFv3-AF may receive IPv4 net with 32 < pxlen < 128.
*/
uint max = (n->type == NET_IP4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
return n->pxlen <= max;
}
/*
* In OSPFv3-AF (RFC 5835), IPv4 address is encoded by just placing it in the
* first 32 bits of IPv6 address and setting remaining bits to zero. Likewise
* for IPv4 prefix, where remaining bits do not matter. We use following
* functions to convert between IPv4 and IPv4-in-IPv6 representations:
*/
static inline ip4_addr ospf3_6to4(ip6_addr a)
{ return _MI4(_I0(a)); }
static inline ip6_addr ospf3_4to6(ip4_addr a)
{ return _MI6(_I(a), 0, 0, 0); }
static inline u32 *
ospf_get_ipv6_prefix(u32 *buf, net_addr *N, u8 *pxopts, u16 *rest)
ospf3_get_prefix(u32 *buf, int af, net_addr *n, u8 *pxopts, u16 *rest)
{
net_addr_ip6 *net = (void *) N;
u8 pxlen = (*buf >> 24);
ip6_addr px = IP6_NONE;
uint pxlen = (*buf >> 24);
*pxopts = (*buf >> 16) & 0xff;
if (rest) *rest = *buf & 0xffff;
buf++;
*net = NET_ADDR_IP6(IP6_NONE, pxlen);
if (pxlen > 0)
_I0(net->prefix) = *buf++;
_I0(px) = *buf++;
if (pxlen > 32)
_I1(net->prefix) = *buf++;
_I1(px) = *buf++;
if (pxlen > 64)
_I2(net->prefix) = *buf++;
_I2(px) = *buf++;
if (pxlen > 96)
_I3(net->prefix) = *buf++;
_I3(px) = *buf++;
/* Clean up remaining bits */
if (pxlen < 128)
net->prefix.addr[pxlen / 32] &= u32_mkmask(pxlen % 32);
px.addr[pxlen / 32] &= u32_mkmask(pxlen % 32);
if (af == NET_IP4)
net_fill_ip4(n, ospf3_6to4(px), pxlen);
else
net_fill_ip6(n, px, pxlen);
return buf;
}
static inline u32 *
ospf_get_ipv6_addr(u32 *buf, ip_addr *addr)
ospf3_put_prefix(u32 *buf, net_addr *n, u8 pxopts, u16 rest)
{
*addr = ipa_from_ip6(*(ip6_addr *) buf);
return buf + 4;
}
static inline u32 *
ospf_put_ipv6_prefix(u32 *buf, net_addr *N, u8 pxopts, u16 rest)
{
net_addr_ip6 *net = (void *) N;
u32 pxlen = net->pxlen;
ip6_addr px = (n->type == NET_IP4) ? ospf3_4to6(net4_prefix(n)) : net6_prefix(n);
uint pxlen = n->pxlen;
*buf++ = ((pxlen << 24) | (pxopts << 16) | rest);
if (pxlen > 0)
*buf++ = _I0(net->prefix);
*buf++ = _I0(px);
if (pxlen > 32)
*buf++ = _I1(net->prefix);
*buf++ = _I1(px);
if (pxlen > 64)
*buf++ = _I2(net->prefix);
*buf++ = _I2(px);
if (pxlen > 96)
*buf++ = _I3(net->prefix);
*buf++ = _I3(px);
return buf;
}
static inline u32 *
ospf_put_ipv6_addr(u32 *buf, ip_addr addr)
ospf3_get_addr(u32 *buf, int af, ip_addr *addr)
{
*(ip6_addr *) buf = ipa_to_ip6(addr);
ip6_addr a;
memcpy(&a, buf, 16);
*addr = (af == NET_IP4) ? ipa_from_ip4(ospf3_6to4(a)) : ipa_from_ip6(a);
return buf + 4;
}
static inline u32 *
ospf3_put_addr(u32 *buf, ip_addr addr)
{
ip6_addr a = ipa_is_ip4(addr) ? ospf3_4to6(ipa_to_ip4(addr)) : ipa_to_ip6(addr);
memcpy(buf, &a, 16);
return buf + 4;
}
@ -838,6 +866,15 @@ static inline int ospf_is_v3(struct ospf_proto *p)
static inline int ospf_get_version(struct ospf_proto *p)
{ return ospf_is_v2(p) ? 2 : 3; }
static inline int ospf_is_ip4(struct ospf_proto *p)
{ return p->p.net_type == NET_IP4; }
static inline int ospf_is_ip6(struct ospf_proto *p)
{ return p->p.net_type == NET_IP6; }
static inline int ospf_get_af(struct ospf_proto *p)
{ return p->p.net_type; }
struct ospf_area *ospf_find_area(struct ospf_proto *p, u32 aid);
static inline struct ospf_area *ospf_main_area(struct ospf_proto *p)

View file

@ -576,20 +576,20 @@ spfa_process_prefixes(struct ospf_proto *p, struct ospf_area *oa)
buf = px->rest;
for (i = 0; i < px->pxcount; i++)
{
net_addr_ip6 net;
net_addr net;
u8 pxopts;
u16 metric;
buf = ospf_get_ipv6_prefix(buf, (net_addr *) &net, &pxopts, &metric);
buf = ospf3_get_prefix(buf, ospf_get_af(p), &net, &pxopts, &metric);
if (pxopts & OPT_PX_NU)
continue;
/* Store the first global address to use it later as a vlink endpoint */
if ((pxopts & OPT_PX_LA) && ipa_zero(src->lb))
src->lb = ipa_from_ip6(net.prefix);
if ((pxopts & OPT_PX_LA) && (net.type == NET_IP6) && ipa_zero(src->lb))
src->lb = ipa_from_ip6(net6_prefix(&net));
add_network(oa, (net_addr *) &net, src->dist + metric, src, i);
add_network(oa, &net, src->dist + metric, src, i);
}
}
}
@ -761,7 +761,7 @@ ospf_rt_sum(struct ospf_area *oa)
if (en->lsa_type == LSA_T_SUM_NET)
{
lsa_parse_sum_net(en, ospf_is_v2(p), &net, &pxopts, &metric);
lsa_parse_sum_net(en, ospf_is_v2(p), ospf_get_af(p), &net, &pxopts, &metric);
if (!ospf_valid_prefix(&net))
{
@ -858,7 +858,7 @@ ospf_rt_sum_tr(struct ospf_area *oa)
net_addr net;
u8 pxopts;
lsa_parse_sum_net(en, ospf_is_v2(p), &net, &pxopts, &metric);
lsa_parse_sum_net(en, ospf_is_v2(p), ospf_get_af(p), &net, &pxopts, &metric);
if (!ospf_valid_prefix(&net))
{
@ -1058,7 +1058,7 @@ decide_nssa_lsa(struct ospf_proto *p, ort *nf, struct ospf_lsa_ext_local *rt)
return 0;
/* We do not store needed data in struct orta, we have to parse the LSA */
lsa_parse_ext(en, ospf_is_v2(p), rt);
lsa_parse_ext(en, ospf_is_v2(p), ospf_get_af(p), rt);
if (rt->pxopts & OPT_PX_NU)
return 0;
@ -1450,7 +1450,7 @@ ospf_ext_spf(struct ospf_proto *p)
DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n",
p->p.name, en->lsa.id, en->lsa.rt, en->lsa_type);
lsa_parse_ext(en, ospf_is_v2(p), &rt);
lsa_parse_ext(en, ospf_is_v2(p), ospf_get_af(p), &rt);
if (!ospf_valid_prefix(&rt.net))
{
@ -1765,7 +1765,11 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
if (ip6_zero(llsa->lladdr))
return NULL;
return new_nexthop(p, ipa_from_ip6(llsa->lladdr), pn->iface, pn->weight);
ip_addr nh = ospf_is_ip4(p) ?
ipa_from_ip4(ospf3_6to4(llsa->lladdr)) :
ipa_from_ip6(llsa->lladdr);
return new_nexthop(p, nh, pn->iface, pn->weight);
}
}
@ -1792,9 +1796,9 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
if (en->lsa.age == LSA_MAXAGE)
return;
if (ospf_is_v3(p) && (en->lsa_type == LSA_T_RT))
if (ospf_is_v3(p) && (oa->options & OPT_V6) && (en->lsa_type == LSA_T_RT))
{
/* In OSPFv3, check V6 flag */
/* In OSPFv3 IPv6 unicast, check V6 flag */
struct ospf_lsa_rt *rt = en->lsa_body;
if (!(rt->options & OPT_V6))
return;

View file

@ -1008,7 +1008,7 @@ prepare_sum3_net_lsa_body(struct ospf_proto *p, ort *nf, u32 metric)
sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_net) +
IPV6_PREFIX_SPACE(nf->fn.addr->pxlen));
sum->metric = metric;
ospf_put_ipv6_prefix(sum->prefix, nf->fn.addr, 0, 0);
ospf3_put_prefix(sum->prefix, nf->fn.addr, 0, 0);
}
static inline void
@ -1097,7 +1097,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
ext->metric = metric & LSA_METRIC_MASK;
u32 *buf = ext->rest;
buf = ospf_put_ipv6_prefix(buf, nf->fn.addr, pbit ? OPT_PX_P : 0, 0);
buf = ospf3_put_prefix(buf, nf->fn.addr, pbit ? OPT_PX_P : 0, 0);
if (ebit)
ext->metric |= LSA_EXT3_EBIT;
@ -1105,7 +1105,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
if (ipa_nonzero(fwaddr))
{
ext->metric |= LSA_EXT3_FBIT;
buf = ospf_put_ipv6_addr(buf, fwaddr);
buf = ospf3_put_addr(buf, fwaddr);
}
if (tag)
@ -1222,7 +1222,7 @@ find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa)
{
WALK_LIST(a, ifa->iface->addrs)
{
if ((a->prefix.type != NET_IP6) ||
if ((a->prefix.type != ospf_get_af(p)) ||
(a->flags & IA_SECONDARY) ||
(a->flags & IA_PEER) ||
(a->scope <= SCOPE_LINK))
@ -1316,39 +1316,47 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
*/
static inline void
lsab_put_prefix(struct ospf_proto *p, net_addr *net, u32 cost)
lsab_put_prefix(struct ospf_proto *p, net_addr *n, u32 cost)
{
void *buf = lsab_alloc(p, IPV6_PREFIX_SPACE(net6_pxlen(net)));
u8 flags = (net6_pxlen(net) < IP6_MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA;
ospf_put_ipv6_prefix(buf, net, flags, cost);
void *buf = lsab_alloc(p, IPV6_PREFIX_SPACE(net_pxlen(n)));
uint max = (n->type == NET_IP4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
u8 flags = (net_pxlen(n) < max) ? 0 : OPT_PX_LA;
ospf3_put_prefix(buf, n, flags, cost);
}
static void
prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
{
struct ospf_lsa_link *ll;
ip_addr nh = ospf_is_ip4(p) ? IPA_NONE : ifa->addr->ip;
int i = 0;
/* Preallocating space for header */
ASSERT(p->lsab_used == 0);
ll = lsab_allocz(p, sizeof(struct ospf_lsa_link));
ll->options = ifa->oa->options | (ifa->priority << 24);
ll->lladdr = ipa_to_ip6(ifa->addr->ip);
ll = NULL; /* buffer might be reallocated later */
lsab_allocz(p, sizeof(struct ospf_lsa_link));
struct ifa *a;
WALK_LIST(a, ifa->iface->addrs)
{
if ((a->prefix.type != NET_IP6) ||
if ((a->prefix.type != ospf_get_af(p)) ||
(a->flags & IA_SECONDARY) ||
(a->scope <= SCOPE_LINK))
continue;
if (ospf_is_ip4(p) && ipa_zero(nh))
nh = a->ip;
lsab_put_prefix(p, &a->prefix, 0);
i++;
}
ll = p->lsab;
/* Filling the preallocated header */
struct ospf_lsa_link *ll = p->lsab;
ll->options = ifa->oa->options | (ifa->priority << 24);
ll->lladdr = ospf_is_ip4(p) ? ospf3_4to6(ipa_to_ip4(nh)) : ipa_to_ip6(nh);
ll->pxcount = i;
if (ipa_zero(nh))
log(L_ERR "%s: Cannot find next hop address for %s", p->p.name, ifa->ifname);
}
static void
@ -1410,7 +1418,7 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
struct ifa *a;
WALK_LIST(a, ifa->iface->addrs)
{
if ((a->prefix.type != NET_IP6) ||
if ((a->prefix.type != ospf_get_af(p)) ||
(a->flags & IA_SECONDARY) ||
(a->flags & IA_PEER) ||
(a->scope <= SCOPE_LINK))
@ -1448,7 +1456,7 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
/* If there are some configured vlinks, find some global address
(even from another area), which will be used as a vlink endpoint. */
if (!EMPTY_LIST(cf->vlink_list) && !host_addr)
if (!EMPTY_LIST(cf->vlink_list) && !host_addr && ospf_is_ip6(p))
{
WALK_LIST(ifa, p->iface_list)
{
@ -1571,7 +1579,7 @@ add_link_lsa(struct ospf_proto *p, struct ospf_lsa_link *ll, int offset, int *px
continue;
/* Skip link-local prefixes */
if ((pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
if (ospf_is_ip6(p) && (pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
continue;
add_prefix(p, pxb, offset, pxc);