diff options
-rw-r--r-- | filter/config.Y | 3 | ||||
-rw-r--r-- | filter/data.h | 1 | ||||
-rw-r--r-- | filter/f-inst.c | 1 | ||||
-rw-r--r-- | lib/route.h | 12 | ||||
-rw-r--r-- | lib/type_test.c | 1 | ||||
-rw-r--r-- | nest/rt-attr.c | 32 | ||||
-rw-r--r-- | nest/rt-dev.c | 2 | ||||
-rw-r--r-- | nest/rt-table.c | 8 | ||||
-rw-r--r-- | proto/babel/babel.c | 6 | ||||
-rw-r--r-- | proto/bgp/attrs.c | 2 | ||||
-rw-r--r-- | proto/bgp/config.Y | 2 | ||||
-rw-r--r-- | proto/bgp/packets.c | 2 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 22 | ||||
-rw-r--r-- | proto/ospf/rt.c | 21 | ||||
-rw-r--r-- | proto/perf/perf.c | 2 | ||||
-rw-r--r-- | proto/rip/rip.c | 4 | ||||
-rw-r--r-- | proto/rpki/rpki.c | 2 | ||||
-rw-r--r-- | proto/static/static.c | 2 | ||||
-rw-r--r-- | sysdep/bsd/krt-sock.c | 3 | ||||
-rw-r--r-- | sysdep/linux/netlink.c | 2 |
20 files changed, 79 insertions, 51 deletions
diff --git a/filter/config.Y b/filter/config.Y index 6af39c10..ca792593 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -285,7 +285,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN, SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST, IF, THEN, ELSE, CASE, TRUE, FALSE, RT, RO, UNKNOWN, GENERIC, - FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, + FROM, GW, NET, MASK, PROTO, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, ROA_CHECK, ASN, SRC, DST, IS_V4, IS_V6, LEN, MAXLEN, @@ -765,7 +765,6 @@ static_attr: GW { $$ = f_new_static_attr(T_IP, SA_GW, 0); } | NET { $$ = f_new_static_attr(T_NET, SA_NET, 1); } | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 1); } - | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 1); } | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); } | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); } | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); } diff --git a/filter/data.h b/filter/data.h index 49b29499..23db4a85 100644 --- a/filter/data.h +++ b/filter/data.h @@ -25,7 +25,6 @@ enum f_sa_code { SA_GW = 1, SA_NET, SA_PROTO, - SA_SOURCE, SA_DEST, SA_IFNAME, SA_IFINDEX, diff --git a/filter/f-inst.c b/filter/f-inst.c index 5eacc716..23271ce7 100644 --- a/filter/f-inst.c +++ b/filter/f-inst.c @@ -536,7 +536,6 @@ case SA_GW: RESULT(sa.type, ip, rta->nh.gw); break; case SA_NET: RESULT(sa.type, net, (*fs->rte)->net->n.addr); break; case SA_PROTO: RESULT(sa.type, s, (*fs->rte)->src->proto->name); break; - case SA_SOURCE: RESULT(sa.type, i, rta->source); break; case SA_DEST: RESULT(sa.type, i, rta->dest); break; case SA_IFNAME: RESULT(sa.type, s, rta->nh.iface ? rta->nh.iface->name : ""); break; case SA_IFINDEX: RESULT(sa.type, i, rta->nh.iface ? rta->nh.iface->index : 0); break; diff --git a/lib/route.h b/lib/route.h index 40ba150d..8fdb5d8b 100644 --- a/lib/route.h +++ b/lib/route.h @@ -85,7 +85,6 @@ typedef struct rta { struct ea_list *eattrs; /* Extended Attribute chain */ struct hostentry *hostentry; /* Hostentry for recursive next-hops */ u16 cached:1; /* Are attributes cached? */ - u16 source:7; /* Route source (RTS_...) */ u16 dest:4; /* Route destination type (RTD_...) */ struct nexthop nh; /* Next hop */ } rta; @@ -131,12 +130,13 @@ static inline int rte_is_reachable(rte *r) typedef struct eattr { word id; /* EA_CODE(PROTOCOL_..., protocol-dependent ID) */ byte flags; /* Protocol-dependent flags */ - byte type:5; /* Attribute type */ + byte type; /* Attribute type */ + byte rfu:5; byte originated:1; /* The attribute has originated locally */ byte fresh:1; /* An uncached attribute (e.g. modified in export filter) */ byte undef:1; /* Explicitly undefined */ - PADDING(unused, 0, 4); + PADDING(unused, 3, 3); union bval u; } eattr; @@ -308,6 +308,12 @@ u32 rt_get_igp_metric(rte *rt); /* From: Advertising router */ extern struct ea_class ea_gen_from; +/* Source: An old method to devise the route source protocol and kind. + * To be superseded in a near future by something more informative. */ +extern struct ea_class ea_gen_source; +static inline u32 rt_get_source_attr(rte *rt) +{ return ea_get_int(rt->attrs->eattrs, &ea_gen_source, 0); } + /* Next hop structures */ #define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK) diff --git a/lib/type_test.c b/lib/type_test.c index 20e7630b..b526db69 100644 --- a/lib/type_test.c +++ b/lib/type_test.c @@ -54,6 +54,7 @@ t_eattr(void) e.id = ~0; e.flags = ~0; e.type = ~0; + e.rfu = ~0; e.originated = ~0; e.fresh = ~0; e.undef = ~0; diff --git a/nest/rt-attr.c b/nest/rt-attr.c index a892bfd5..39fd7db4 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -92,6 +92,22 @@ const char * const rta_src_names[RTS_MAX] = { [RTS_RPKI] = "RPKI", }; +static void +ea_gen_source_format(const eattr *a, byte *buf, uint size) +{ + if ((a->u.data >= RTS_MAX) || !rta_src_names[a->u.data]) + bsnprintf(buf, size, "unknown"); + else + bsnprintf(buf, size, "%s", rta_src_names[a->u.data]); +} + +struct ea_class ea_gen_source = { + .name = "source", + .type = T_ENUM_RTS, + .readonly = 1, + .format = ea_gen_source_format, +}; + const char * rta_dest_names[RTD_MAX] = { [RTD_NONE] = "", [RTD_UNICAST] = "unicast", @@ -1234,7 +1250,6 @@ rta_hash(rta *a) #define MIX(f) mem_hash_mix(&h, &(a->f), sizeof(a->f)); #define BMIX(f) mem_hash_mix_num(&h, a->f); MIX(hostentry); - BMIX(source); BMIX(dest); #undef MIX @@ -1244,8 +1259,7 @@ rta_hash(rta *a) static inline int rta_same(rta *x, rta *y) { - return (x->source == y->source && - x->dest == y->dest && + return (x->dest == y->dest && x->hostentry == y->hostentry && nexthop_same(&(x->nh), &(y->nh)) && ea_same(x->eattrs, y->eattrs)); @@ -1388,15 +1402,10 @@ rta_do_cow(rta *o, linpool *lp) void rta_dump(rta *a) { - static char *rts[] = { "", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE", - "RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP", - "RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1", - "RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" }; static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" }; - debug("uc=%d %s %s h=%04x", - a->uc, rts[a->source], - rtd[a->dest], a->hash_key); + debug("uc=%d %s h=%04x", + a->uc, rtd[a->dest], a->hash_key); if (!a->cached) debug(" !CACHED"); if (a->dest == RTD_UNICAST) @@ -1441,8 +1450,6 @@ rta_dump_all(void) void rta_show(struct cli *c, rta *a) { - cli_printf(c, -1008, "\tType: %s", rta_src_names[a->source]); - for(ea_list *eal = a->eattrs; eal; eal=eal->next) for(int i=0; i<eal->count; i++) ea_show(c, &eal->attrs[i]); @@ -1476,6 +1483,7 @@ rta_init(void) ea_register_init(&ea_gen_preference); ea_register_init(&ea_gen_igp_metric); ea_register_init(&ea_gen_from); + ea_register_init(&ea_gen_source); } /* diff --git a/nest/rt-dev.c b/nest/rt-dev.c index ffd5afd5..af6506f6 100644 --- a/nest/rt-dev.c +++ b/nest/rt-dev.c @@ -83,12 +83,12 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad) struct rte_src *src = rt_get_source(P, ad->iface->index); rta a0 = { - .source = RTS_DEVICE, .dest = RTD_UNICAST, .nh.iface = ad->iface, }; ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, c->preference); + ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_DEVICE); a = rta_lookup(&a0); e = rte_get_temp(a, src); diff --git a/nest/rt-table.c b/nest/rt-table.c index e8b04e0b..4f119ac0 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -2588,7 +2588,7 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i trie_add_prefix(tab_flow->flowspec_trie, &dst, (nb ? nb->n.addr->pxlen : 0), max_pxlen); /* No best-match BGP route -> no flowspec */ - if (!rb || (rb->attrs->source != RTS_BGP)) + if (!rb || (rt_get_source_attr(rb) != RTS_BGP)) return 0; /* Find ORIGINATOR_ID values */ @@ -2620,7 +2620,7 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i continue; rte *rc = nc->routes; - if (rc->attrs->source != RTS_BGP) + if (rt_get_source_attr(rc) != RTS_BGP) return 0; if (rta_get_first_asn(rc->attrs) != asn_b) @@ -2637,7 +2637,7 @@ static rte * rt_flowspec_update_rte(rtable *tab, rte *r) { #ifdef CONFIG_BGP - if (r->attrs->source != RTS_BGP) + if (rt_get_source_attr(r) != RTS_BGP) return NULL; struct bgp_channel *bc = (struct bgp_channel *) r->sender; @@ -3471,7 +3471,7 @@ rt_get_igp_metric(rte *rt) if (ea) return ea->u.data; - if (rt->attrs->source == RTS_DEVICE) + if (rt_get_source_attr(rt) == RTS_DEVICE) return 0; if (rt->src->proto->rte_igp_metric) diff --git a/proto/babel/babel.c b/proto/babel/babel.c index cd221c7b..a7dcee09 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -645,12 +645,13 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) { struct { ea_list l; - eattr a[5]; + eattr a[6]; } eattrs = { .l.count = ARRAY_SIZE(eattrs.a), .a = { EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, c->preference), EA_LITERAL_STORE_ADATA(&ea_gen_from, 0, &r->neigh->addr, sizeof(r->neigh->addr)), + EA_LITERAL_EMBEDDED(&ea_gen_source, 0, RTS_BABEL), EA_LITERAL_EMBEDDED(&ea_babel_metric, 0, r->metric), EA_LITERAL_STORE_ADATA(&ea_babel_router_id, 0, &r->router_id, sizeof(r->router_id)), EA_LITERAL_EMBEDDED(&ea_babel_seqno, 0, r->seqno), @@ -658,7 +659,6 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) }; rta a0 = { - .source = RTS_BABEL, .dest = RTD_UNICAST, .nh.gw = r->next_hop, .nh.iface = r->neigh->ifa->iface, @@ -683,11 +683,11 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e) { /* Unreachable */ rta a0 = { - .source = RTS_BABEL, .dest = RTD_UNREACHABLE, }; ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, 1); + ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_BABEL); rta *a = rta_lookup(&a0); rte *rte = rte_get_temp(a, p->p.main_source); diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index 097ba9a2..1efc26ce 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -402,7 +402,7 @@ bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad) static inline int bgp_init_aigp_metric(rte *e, u64 *metric, const struct adata **ad) { - if (e->attrs->source == RTS_BGP) + if (rt_get_source_attr(e) == RTS_BGP) return 0; *metric = rt_get_igp_metric(e); diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index b4d8b83f..24f3ec8f 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -43,7 +43,7 @@ CF_KEYWORDS(CEASE, PREFIX, LIMIT, HIT, ADMINISTRATIVE, SHUTDOWN, RESET, PEER, CF_GRAMMAR -toksym: BGP_MED | BGP_LOCAL_PREF ; +toksym: BGP_MED | BGP_LOCAL_PREF | SOURCE ; proto: bgp_proto '}' ; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 62d60e9a..0aa4dc40 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2474,11 +2474,11 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis { a = allocz(RTA_MAX_SIZE); - a->source = RTS_BGP; a->eattrs = ea; ea_set_attr_data(&a->eattrs, &ea_gen_from, 0, &s->proto->remote_ip, sizeof(ip_addr)); ea_set_attr_u32(&a->eattrs, &ea_gen_preference, 0, c->c.preference); + ea_set_attr_u32(&a->eattrs, &ea_gen_source, 0, RTS_BGP); c->desc->decode_next_hop(s, nh, nh_len, a); bgp_finish_attrs(s, a); diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index 427c2c86..731adaa5 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -392,15 +392,18 @@ ospf_rte_better(struct rte *new, struct rte *old) if (new_metric1 == LSINFINITY) return 0; - if(new->attrs->source < old->attrs->source) return 1; - if(new->attrs->source > old->attrs->source) return 0; + u32 ns = rt_get_source_attr(new); + u32 os = rt_get_source_attr(old); - if(new->attrs->source == RTS_OSPF_EXT2) + if (ns < os) return 1; + if (ns > os) return 0; + + if (ns == RTS_OSPF_EXT2) { u32 old_metric2 = ea_get_int(old->attrs->eattrs, &ea_ospf_metric2, LSINFINITY); u32 new_metric2 = ea_get_int(new->attrs->eattrs, &ea_ospf_metric2, LSINFINITY); - if(new_metric2 < old_metric2) return 1; - if(new_metric2 > old_metric2) return 0; + if (new_metric2 < old_metric2) return 1; + if (new_metric2 > old_metric2) return 0; } u32 old_metric1 = ea_get_int(old->attrs->eattrs, &ea_ospf_metric1, LSINFINITY); @@ -413,7 +416,7 @@ ospf_rte_better(struct rte *new, struct rte *old) static u32 ospf_rte_igp_metric(struct rte *rt) { - if (rt->attrs->source == RTS_OSPF_EXT2) + if (rt_get_source_attr(rt) == RTS_OSPF_EXT2) return IGP_METRIC_UNKNOWN; return ea_get_int(rt->attrs->eattrs, &ea_ospf_metric1, LSINFINITY); @@ -571,7 +574,8 @@ ospf_get_route_info(rte * rte, byte * buf) { char *type = "<bug>"; - switch (rte->attrs->source) + uint source = rt_get_source_attr(rte); + switch (source) { case RTS_OSPF: type = "I"; @@ -589,10 +593,10 @@ ospf_get_route_info(rte * rte, byte * buf) buf += bsprintf(buf, " %s", type); buf += bsprintf(buf, " (%d/%d", rt_get_preference(rte), ea_get_int(rte->attrs->eattrs, &ea_ospf_metric1, LSINFINITY)); - if (rte->attrs->source == RTS_OSPF_EXT2) + if (source == RTS_OSPF_EXT2) buf += bsprintf(buf, "/%d", ea_get_int(rte->attrs->eattrs, &ea_ospf_metric2, LSINFINITY)); buf += bsprintf(buf, ")"); - if (rte->attrs->source == RTS_OSPF_EXT1 || rte->attrs->source == RTS_OSPF_EXT2) + if (source == RTS_OSPF_EXT1 || source == RTS_OSPF_EXT2) { eattr *ea = ea_find(rte->attrs->eattrs, &ea_ospf_tag); if (ea && (ea->u.data > 0)) diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index ddc5b162..91739056 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -2004,11 +2004,19 @@ static inline int ort_changed(ort *nf, rta *nr) { rta *or = nf->old_rta; - return !or || + + if (!or || (nf->n.metric1 != nf->old_metric1) || (nf->n.metric2 != nf->old_metric2) || (nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid) || - (nr->source != or->source) || (nr->dest != or->dest) || - !nexthop_same(&(nr->nh), &(or->nh)); + (nr->dest != or->dest) || + !nexthop_same(&(nr->nh), &(or->nh))) + return 1; + + if ( ea_get_int(nr->eattrs, &ea_gen_source, 0) + != ea_get_int(or->eattrs, &ea_gen_source, 0)) + return 1; + + return 0; } static void @@ -2053,7 +2061,6 @@ again1: if (nf->n.type) /* Add the route */ { rta a0 = { - .source = nf->n.type, .dest = RTD_UNICAST, .nh = *(nf->n.nhs), }; @@ -2067,7 +2074,7 @@ again1: struct { ea_list l; - eattr a[5]; + eattr a[6]; } eattrs; eattrs.l = (ea_list) {}; @@ -2075,6 +2082,9 @@ again1: eattrs.a[eattrs.l.count++] = EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, p->p.main_channel->preference); + eattrs.a[eattrs.l.count++] = + EA_LITERAL_EMBEDDED(&ea_gen_source, 0, nf->n.type); + eattrs.a[eattrs.l.count++] = EA_LITERAL_EMBEDDED(&ea_ospf_metric1, 0, nf->n.metric1); @@ -2089,6 +2099,7 @@ again1: eattrs.a[eattrs.l.count++] = EA_LITERAL_EMBEDDED(&ea_ospf_router_id, 0, nf->n.rid); + ASSERT_DIE(ARRAY_SIZE(eattrs.a) >= eattrs.l.count); a0.eattrs = &eattrs.l; rta *a = rta_lookup(&a0); diff --git a/proto/perf/perf.c b/proto/perf/perf.c index 47a2867d..4329556c 100644 --- a/proto/perf/perf.c +++ b/proto/perf/perf.c @@ -143,7 +143,6 @@ perf_loop(void *data) if (!p->attrs_per_rte || !(i % p->attrs_per_rte)) { struct rta a0 = { - .source = RTS_PERF, .dest = RTD_UNICAST, .nh.iface = p->ifa->iface, .nh.gw = gw, @@ -151,6 +150,7 @@ perf_loop(void *data) }; ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, p->p.main_channel->preference); + ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_PERF); p->data[i].a = rta_lookup(&a0); } diff --git a/proto/rip/rip.c b/proto/rip/rip.c index f5442606..f7f34c27 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -152,17 +152,17 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en) { /* Update */ rta a0 = { - .source = RTS_RIP, .dest = RTD_UNICAST, }; struct { ea_list l; - eattr a[2]; + eattr a[3]; } ea_block = { .l.count = ARRAY_SIZE(ea_block.a), .a = { EA_LITERAL_EMBEDDED(&ea_gen_preference, 0, p->p.main_channel->preference), + EA_LITERAL_EMBEDDED(&ea_gen_source, 0, RTS_RIP), EA_LITERAL_EMBEDDED(&ea_rip_metric, 0, rt->metric), }, }; diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index af963f49..56d8add2 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -121,11 +121,11 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_ struct rpki_proto *p = cache->p; rta a0 = { - .source = RTS_RPKI, .dest = RTD_NONE, }; ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, channel->preference); + ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_RPKI); rta *a = rta_lookup(&a0); rte *e = rte_get_temp(a, p->p.main_source); diff --git a/proto/static/static.c b/proto/static/static.c index ff833b16..1400e985 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -55,9 +55,9 @@ static_announce_rte(struct static_proto *p, struct static_route *r) { rta *a = allocz(RTA_MAX_SIZE); struct rte_src *src = static_get_source(p, r->index); - a->source = RTS_STATIC; a->dest = r->dest; ea_set_attr_u32(&a->eattrs, &ea_gen_preference, 0, p->p.main_channel->preference); + ea_set_attr_u32(&a->eattrs, &ea_gen_source, 0, RTS_STATIC); if (r->dest == RTD_UNICAST) { diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index bc6b1839..61ac7a5c 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -520,9 +520,10 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan) rta a = { .src = p->p.main_source, - .source = RTS_INHERIT, }; + ea_set_attr_u32(&a->eattrs, &ea_gen_source, 0, RTS_INHERIT); + /* reject/blackhole routes have also set RTF_GATEWAY, we wil check them first. */ diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index c506c71c..e0219ce0 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -1854,7 +1854,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h) nl_announce_route(s); rta *ra = lp_allocz(s->pool, RTA_MAX_SIZE); - ra->source = RTS_INHERIT; + ea_set_attr_u32(&ra->eattrs, &ea_gen_source, 0, RTS_INHERIT); if (a[RTA_FLOW]) s->rta_flow = rta_get_u32(a[RTA_FLOW]); |