Merge branch 'frr/pull/822' ("EVPN fixes")

Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
David Lamparter 2017-08-09 21:34:10 +02:00
commit 695bb8f0d1
33 changed files with 2845 additions and 869 deletions

View File

@ -2606,10 +2606,9 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
stream_putc(s, pkt_safi); /* SAFI */ stream_putc(s, pkt_safi); /* SAFI */
/* Nexthop AFI */ /* Nexthop AFI */
if (afi == AFI_IP && safi == SAFI_UNICAST) { if (afi == AFI_IP
&& (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST))
nh_afi = peer_cap_enhe(peer, afi, safi) ? AFI_IP6 : AFI_IP; nh_afi = peer_cap_enhe(peer, afi, safi) ? AFI_IP6 : AFI_IP;
} else if (safi == SAFI_LABELED_UNICAST)
nh_afi = afi;
else else
nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len); nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len);
@ -2800,9 +2799,8 @@ static void bgp_packet_mpattr_tea(struct bgp *bgp, struct peer *peer,
if (attrlenfield > 0xff) { if (attrlenfield > 0xff) {
/* 2-octet length field */ /* 2-octet length field */
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN);
| BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, attrtype); stream_putc(s, attrtype);
stream_putw(s, attrlenfield & 0xffff); stream_putw(s, attrlenfield & 0xffff);
} else { } else {
@ -3040,15 +3038,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
&& (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) { && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) {
if (attr->community->size * 4 > 255) { if (attr->community->size * 4 > 255) {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN); | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_COMMUNITIES); stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putw(s, attr->community->size * 4); stream_putw(s, attr->community->size * 4);
} else { } else {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_COMMUNITIES); stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putc(s, attr->community->size * 4); stream_putc(s, attr->community->size * 4);
} }
@ -3062,15 +3059,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
PEER_FLAG_SEND_LARGE_COMMUNITY) PEER_FLAG_SEND_LARGE_COMMUNITY)
&& (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) { && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) {
if (attr->lcommunity->size * 12 > 255) { if (attr->lcommunity->size * 12 > 255) {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN); | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putw(s, attr->lcommunity->size * 12); stream_putw(s, attr->lcommunity->size * 12);
} else { } else {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putc(s, attr->lcommunity->size * 12); stream_putc(s, attr->lcommunity->size * 12);
} }
@ -3122,16 +3118,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
if (peer->sort == BGP_PEER_IBGP if (peer->sort == BGP_PEER_IBGP
|| peer->sort == BGP_PEER_CONFED) { || peer->sort == BGP_PEER_CONFED) {
if (attr->ecommunity->size * 8 > 255) { if (attr->ecommunity->size * 8 > 255) {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_EXTLEN);
| BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_EXT_COMMUNITIES); stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
stream_putw(s, attr->ecommunity->size * 8); stream_putw(s, attr->ecommunity->size * 8);
} else { } else {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_EXT_COMMUNITIES); stream_putc(s, BGP_ATTR_EXT_COMMUNITIES);
stream_putc(s, attr->ecommunity->size * 8); stream_putc(s, attr->ecommunity->size * 8);
} }
@ -3197,9 +3191,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
label_index = attr->label_index; label_index = attr->label_index;
if (label_index != BGP_INVALID_LABEL_INDEX) { if (label_index != BGP_INVALID_LABEL_INDEX) {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_PREFIX_SID); stream_putc(s, BGP_ATTR_PREFIX_SID);
stream_putc(s, 10); stream_putc(s, 10);
stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX); stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);
@ -3227,9 +3220,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
*/ */
aspath = aspath_delete_confed_seq(aspath); aspath = aspath_delete_confed_seq(aspath);
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_EXTLEN);
| BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_AS4_PATH); stream_putc(s, BGP_ATTR_AS4_PATH);
aspath_sizep = stream_get_endp(s); aspath_sizep = stream_get_endp(s);
stream_putw(s, 0); stream_putw(s, 0);
@ -3414,15 +3406,14 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
/* Community attribute. */ /* Community attribute. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) { if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
if (attr->community->size * 4 > 255) { if (attr->community->size * 4 > 255) {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN); | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_COMMUNITIES); stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putw(s, attr->community->size * 4); stream_putw(s, attr->community->size * 4);
} else { } else {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_COMMUNITIES); stream_putc(s, BGP_ATTR_COMMUNITIES);
stream_putc(s, attr->community->size * 4); stream_putc(s, attr->community->size * 4);
} }
@ -3432,15 +3423,14 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
/* Large Community attribute. */ /* Large Community attribute. */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) { if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) {
if (attr->lcommunity->size * 12 > 255) { if (attr->lcommunity->size * 12 > 255) {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_TRANS
| BGP_ATTR_FLAG_EXTLEN); | BGP_ATTR_FLAG_EXTLEN);
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putw(s, attr->lcommunity->size * 12); stream_putw(s, attr->lcommunity->size * 12);
} else { } else {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES);
stream_putc(s, attr->lcommunity->size * 12); stream_putc(s, attr->lcommunity->size * 12);
} }
@ -3485,9 +3475,8 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
/* Prefix SID */ /* Prefix SID */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) { if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) {
if (attr->label_index != BGP_INVALID_LABEL_INDEX) { if (attr->label_index != BGP_INVALID_LABEL_INDEX) {
stream_putc(s, stream_putc(s, BGP_ATTR_FLAG_OPTIONAL
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
| BGP_ATTR_FLAG_TRANS);
stream_putc(s, BGP_ATTR_PREFIX_SID); stream_putc(s, BGP_ATTR_PREFIX_SID);
stream_putc(s, 10); stream_putc(s, 10);
stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX); stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX);

View File

@ -169,7 +169,7 @@ extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag,
prefix_copy(src, dst); prefix_copy(src, dst);
memset(dst, 0, sizeof(struct prefix)); memset(dst, 0, sizeof(struct prefix));
p_evpn_p = &(dst->u.prefix_evpn); p_evpn_p = &(dst->u.prefix_evpn);
dst->family = AF_ETHERNET; dst->family = AF_EVPN;
p_evpn_p->route_type = evpn_type; p_evpn_p->route_type = evpn_type;
if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) { if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) {
p_evpn_p->eth_tag = eth_tag; p_evpn_p->eth_tag = eth_tag;

View File

@ -347,9 +347,9 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
s = zclient->obuf; s = zclient->obuf;
stream_reset(s); stream_reset(s);
zclient_create_header( zclient_create_header(s, add ? ZEBRA_REMOTE_MACIP_ADD
s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL, : ZEBRA_REMOTE_MACIP_DEL,
bgp->vrf_id); bgp->vrf_id);
stream_putl(s, vpn->vni); stream_putl(s, vpn->vni);
stream_put(s, &p->prefix.mac.octet, ETH_ALEN); /* Mac Addr */ stream_put(s, &p->prefix.mac.octet, ETH_ALEN); /* Mac Addr */
/* IP address length and IP address, if any. */ /* IP address length and IP address, if any. */
@ -400,9 +400,9 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
s = zclient->obuf; s = zclient->obuf;
stream_reset(s); stream_reset(s);
zclient_create_header( zclient_create_header(s, add ? ZEBRA_REMOTE_VTEP_ADD
s, add ? ZEBRA_REMOTE_VTEP_ADD : ZEBRA_REMOTE_VTEP_DEL, : ZEBRA_REMOTE_VTEP_DEL,
bgp->vrf_id); bgp->vrf_id);
stream_putl(s, vpn->vni); stream_putl(s, vpn->vni);
if (IS_EVPN_PREFIX_IPADDR_V4(p)) if (IS_EVPN_PREFIX_IPADDR_V4(p))
stream_put_in_addr(s, &p->prefix.ip.ipaddr_v4); stream_put_in_addr(s, &p->prefix.ip.ipaddr_v4);
@ -472,7 +472,7 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr)
{ {
struct ecommunity ecom_tmp; struct ecommunity ecom_tmp;
struct ecommunity_val eval; struct ecommunity_val eval;
struct ecommunity *ecom_mm; u_int8_t *ecom_val_ptr;
int i; int i;
u_int8_t *pnt; u_int8_t *pnt;
int type = 0; int type = 0;
@ -482,7 +482,7 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr)
encode_mac_mobility_extcomm(0, seq_num, &eval); encode_mac_mobility_extcomm(0, seq_num, &eval);
/* Find current MM ecommunity */ /* Find current MM ecommunity */
ecom_mm = NULL; ecom_val_ptr = NULL;
if (attr->ecommunity) { if (attr->ecommunity) {
for (i = 0; i < attr->ecommunity->size; i++) { for (i = 0; i < attr->ecommunity->size; i++) {
@ -493,17 +493,17 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr)
if (type == ECOMMUNITY_ENCODE_EVPN if (type == ECOMMUNITY_ENCODE_EVPN
&& sub_type && sub_type
== ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) { == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) {
ecom_mm = (struct ecommunity *) ecom_val_ptr =
attr->ecommunity->val (u_int8_t *)(attr->ecommunity->val
+ (i * 8); + (i * 8));
break; break;
} }
} }
} }
/* Update the existing MM ecommunity */ /* Update the existing MM ecommunity */
if (ecom_mm) { if (ecom_val_ptr) {
memcpy(ecom_mm->val, eval.val, sizeof(char) * ECOMMUNITY_SIZE); memcpy(ecom_val_ptr, eval.val, sizeof(char) * ECOMMUNITY_SIZE);
} }
/* Add MM to existing */ /* Add MM to existing */
else { else {
@ -704,7 +704,7 @@ static int evpn_route_is_sticky(struct bgp *bgp, struct bgp_node *rn)
static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
afi_t afi, safi_t safi, struct bgp_node *rn, afi_t afi, safi_t safi, struct bgp_node *rn,
struct attr *attr, int add, int vni_table, struct attr *attr, int add, int vni_table,
struct bgp_info **ri) struct bgp_info **ri, u_char flags)
{ {
struct bgp_info *tmp_ri; struct bgp_info *tmp_ri;
struct bgp_info *local_ri, *remote_ri; struct bgp_info *local_ri, *remote_ri;
@ -751,8 +751,11 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
* remote, we have to initiate appropriate MAC mobility steps. * remote, we have to initiate appropriate MAC mobility steps.
* This * This
* is applicable when updating the VNI routing table. * is applicable when updating the VNI routing table.
* We need to skip mobility steps for g/w macs (local mac on g/w
* SVI) advertised in EVPN.
* This will ensure that local routes are preferred for g/w macs
*/ */
if (remote_ri) { if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MAC_TYPE_GW)) {
u_int32_t cur_seqnum; u_int32_t cur_seqnum;
/* Add MM extended community to route. */ /* Add MM extended community to route. */
@ -811,7 +814,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
* and schedule for processing. * and schedule for processing.
*/ */
static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
struct prefix_evpn *p, u_char sticky) struct prefix_evpn *p, u_char flags)
{ {
struct bgp_node *rn; struct bgp_node *rn;
struct attr attr; struct attr attr;
@ -828,7 +831,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
attr.nexthop = vpn->originator_ip; attr.nexthop = vpn->originator_ip;
attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip;
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
attr.sticky = sticky; attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0;
/* Set up RT and ENCAP extended community. */ /* Set up RT and ENCAP extended community. */
build_evpn_route_extcomm(vpn, &attr); build_evpn_route_extcomm(vpn, &attr);
@ -839,7 +842,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
/* Create or update route entry. */ /* Create or update route entry. */
route_change = update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, route_change = update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr,
1, 1, &ri); 1, 1, &ri, flags);
assert(ri); assert(ri);
attr_new = ri->attr; attr_new = ri->attr;
@ -860,7 +863,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi,
(struct prefix *)p, &vpn->prd); (struct prefix *)p, &vpn->prd);
update_evpn_route_entry(bgp, vpn, afi, safi, rn, attr_new, 1, 0, update_evpn_route_entry(bgp, vpn, afi, safi, rn, attr_new, 1, 0,
&global_ri); &global_ri, flags);
/* Schedule for processing and unlock node. */ /* Schedule for processing and unlock node. */
bgp_process(bgp, rn, afi, safi); bgp_process(bgp, rn, afi, safi);
@ -998,10 +1001,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
if (evpn_route_is_sticky(bgp, rn)) if (evpn_route_is_sticky(bgp, rn))
update_evpn_route_entry(bgp, vpn, afi, safi, rn, update_evpn_route_entry(bgp, vpn, afi, safi, rn,
&attr_sticky, 0, 1, &ri); &attr_sticky, 0, 1, &ri, 0);
else else
update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr,
0, 1, &ri); 0, 1, &ri, 0);
/* If a local route exists for this prefix, we need to update /* If a local route exists for this prefix, we need to update
* the global routing table too. * the global routing table too.
@ -1022,7 +1025,7 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn)
(struct prefix *)evp, &vpn->prd); (struct prefix *)evp, &vpn->prd);
assert(rd_rn); assert(rd_rn);
update_evpn_route_entry(bgp, vpn, afi, safi, rd_rn, attr_new, 0, update_evpn_route_entry(bgp, vpn, afi, safi, rd_rn, attr_new, 0,
0, &global_ri); 0, &global_ri, 0);
/* Schedule for processing and unlock node. */ /* Schedule for processing and unlock node. */
bgp_process(bgp, rd_rn, afi, safi); bgp_process(bgp, rd_rn, afi, safi);
@ -1190,6 +1193,12 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn,
{ {
struct prefix_evpn p; struct prefix_evpn p;
/* If VNI is not live, we only need to update the originator ip */
if (!is_vni_live(vpn)) {
vpn->originator_ip = originator_ip;
return 0;
}
/* Need to withdraw type-3 route as the originator IP is part /* Need to withdraw type-3 route as the originator IP is part
* of the key. * of the key.
*/ */
@ -1631,8 +1640,8 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
global_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, global_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi,
(struct prefix *)&p, &vpn->prd); (struct prefix *)&p, &vpn->prd);
update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, 0, update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, 0, &ri,
&ri); 0);
/* Schedule for processing and unlock node. */ /* Schedule for processing and unlock node. */
bgp_process(bgp, global_rn, afi, safi); bgp_process(bgp, global_rn, afi, safi);
@ -1665,7 +1674,7 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn)
(struct prefix *)evp, &vpn->prd); (struct prefix *)evp, &vpn->prd);
assert(global_rn); assert(global_rn);
update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1,
0, &global_ri); 0, &global_ri, 0);
/* Schedule for processing and unlock node. */ /* Schedule for processing and unlock node. */
bgp_process(bgp, global_rn, afi, safi); bgp_process(bgp, global_rn, afi, safi);
@ -1798,7 +1807,7 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
/* Make EVPN prefix. */ /* Make EVPN prefix. */
memset(&p, 0, sizeof(struct prefix_evpn)); memset(&p, 0, sizeof(struct prefix_evpn));
p.family = AF_ETHERNET; p.family = AF_EVPN;
p.prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN; p.prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN;
p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE; p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
@ -1887,7 +1896,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
/* Make EVPN prefix. */ /* Make EVPN prefix. */
memset(&p, 0, sizeof(struct prefix_evpn)); memset(&p, 0, sizeof(struct prefix_evpn));
p.family = AF_ETHERNET; p.family = AF_EVPN;
p.prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN; p.prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN;
p.prefix.route_type = BGP_EVPN_IMET_ROUTE; p.prefix.route_type = BGP_EVPN_IMET_ROUTE;
@ -1952,7 +1961,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
/* Make EVPN prefix. */ /* Make EVPN prefix. */
memset(&p, 0, sizeof(struct prefix_evpn)); memset(&p, 0, sizeof(struct prefix_evpn));
p.family = AF_ETHERNET; p.family = AF_EVPN;
p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE; p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
/* Additional information outside of prefix - ESI and GW IP */ /* Additional information outside of prefix - ESI and GW IP */
@ -2021,7 +2030,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p,
struct evpn_addr *p_evpn_p; struct evpn_addr *p_evpn_p;
memset(&temp, 0, 16); memset(&temp, 0, 16);
if (p->family != AF_ETHERNET) if (p->family != AF_EVPN)
return; return;
p_evpn_p = &(p->u.prefix_evpn); p_evpn_p = &(p->u.prefix_evpn);
@ -2204,7 +2213,7 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len)
PREFIX2STR_BUFFER)); PREFIX2STR_BUFFER));
} }
} else { } else {
/* Currently, this is to cater to other AF_ETHERNET code. */ /* For EVPN route types not supported yet. */
} }
return (buf); return (buf);
@ -2586,7 +2595,7 @@ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
* Handle add of a local MACIP. * Handle add of a local MACIP.
*/ */
int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
struct ipaddr *ip, u_char sticky) struct ipaddr *ip, u_char flags)
{ {
struct bgpevpn *vpn; struct bgpevpn *vpn;
struct prefix_evpn p; struct prefix_evpn p;
@ -2606,13 +2615,15 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
/* Create EVPN type-2 route and schedule for processing. */ /* Create EVPN type-2 route and schedule for processing. */
build_evpn_type2_prefix(&p, mac, ip); build_evpn_type2_prefix(&p, mac, ip);
if (update_evpn_route(bgp, vpn, &p, sticky)) { if (update_evpn_route(bgp, vpn, &p, flags)) {
char buf[ETHER_ADDR_STRLEN]; char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN];
zlog_err( zlog_err(
"%u:Failed to create Type-2 route, VNI %u %sMAC %s IP %s", "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s",
bgp->vrf_id, vpn->vni, sticky ? "sticky" : "", bgp->vrf_id, vpn->vni,
CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky gateway"
: "",
prefix_mac2str(mac, buf, sizeof(buf)), prefix_mac2str(mac, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2))); ipaddr2str(ip, buf2, sizeof(buf2)));
return -1; return -1;
@ -2671,14 +2682,15 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
/* Lookup VNI. If present and no change, exit. */ /* Lookup VNI. If present and no change, exit. */
vpn = bgp_evpn_lookup_vni(bgp, vni); vpn = bgp_evpn_lookup_vni(bgp, vni);
if (vpn && is_vni_live(vpn)) { if (vpn) {
if (IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)) if (is_vni_live(vpn)
&& IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip))
/* Probably some other param has changed that we don't /* Probably some other param has changed that we don't
* care about. */ * care about. */
return 0; return 0;
/* Local tunnel endpoint IP address has changed */ /* Local tunnel endpoint IP address has changed */
return handle_tunnel_ip_change(bgp, vpn, originator_ip); handle_tunnel_ip_change(bgp, vpn, originator_ip);
} }
/* Create or update as appropriate. */ /* Create or update as appropriate. */
@ -2692,6 +2704,10 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
} }
} }
/* if the VNI is live already, there is nothibng more to do */
if (is_vni_live(vpn))
return 0;
/* Mark as "live" */ /* Mark as "live" */
SET_FLAG(vpn->flags, VNI_FLAG_LIVE); SET_FLAG(vpn->flags, VNI_FLAG_LIVE);

View File

@ -42,7 +42,7 @@ extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip); struct ethaddr *mac, struct ipaddr *ip);
extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni,
struct ethaddr *mac, struct ipaddr *ip, struct ethaddr *mac, struct ipaddr *ip,
u_char sticky); u_char flags);
extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni); extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni);
extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
struct in_addr originator_ip); struct in_addr originator_ip);

View File

@ -58,6 +58,9 @@ struct bgpevpn {
#define VNI_FLAG_IMPRT_CFGD 0x8 /* Import RT is user configured */ #define VNI_FLAG_IMPRT_CFGD 0x8 /* Import RT is user configured */
#define VNI_FLAG_EXPRT_CFGD 0x10 /* Export RT is user configured */ #define VNI_FLAG_EXPRT_CFGD 0x10 /* Export RT is user configured */
/* Flag to indicate if we are advertising the g/w mac ip for this VNI*/
u_int8_t advertise_gw_macip;
/* Id for deriving the RD automatically for this VNI */ /* Id for deriving the RD automatically for this VNI */
u_int16_t rd_id; u_int16_t rd_id;
@ -171,7 +174,7 @@ static inline void build_evpn_type2_prefix(struct prefix_evpn *p,
struct ipaddr *ip) struct ipaddr *ip)
{ {
memset(p, 0, sizeof(struct prefix_evpn)); memset(p, 0, sizeof(struct prefix_evpn));
p->family = AF_ETHERNET; p->family = AF_EVPN;
p->prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN; p->prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN;
p->prefix.route_type = BGP_EVPN_MAC_IP_ROUTE; p->prefix.route_type = BGP_EVPN_MAC_IP_ROUTE;
memcpy(&p->prefix.mac.octet, mac->octet, ETH_ALEN); memcpy(&p->prefix.mac.octet, mac->octet, ETH_ALEN);
@ -184,7 +187,7 @@ static inline void build_evpn_type3_prefix(struct prefix_evpn *p,
struct in_addr originator_ip) struct in_addr originator_ip)
{ {
memset(p, 0, sizeof(struct prefix_evpn)); memset(p, 0, sizeof(struct prefix_evpn));
p->family = AF_ETHERNET; p->family = AF_EVPN;
p->prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN; p->prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN;
p->prefix.route_type = BGP_EVPN_IMET_ROUTE; p->prefix.route_type = BGP_EVPN_IMET_ROUTE;
p->prefix.ip.ipa_type = IPADDR_V4; p->prefix.ip.ipa_type = IPADDR_V4;

View File

@ -195,6 +195,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn)
vty_out(vty, " RD: %s\n", vty_out(vty, " RD: %s\n",
prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN)); prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN));
vty_out(vty, " Originator IP: %s\n", inet_ntoa(vpn->originator_ip)); vty_out(vty, " Originator IP: %s\n", inet_ntoa(vpn->originator_ip));
vty_out(vty, " Advertise-gw-macip : %s\n",
vpn->advertise_gw_macip ? "Yes" : "No");
vty_out(vty, " Import Route Target:\n"); vty_out(vty, " Import Route Target:\n");
for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) { for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
@ -1641,6 +1643,51 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp)
vty); vty);
} }
/*
* evpn - enable advertisement of default g/w
*/
static void evpn_set_advertise_default_gw(struct bgp *bgp, struct bgpevpn *vpn)
{
if (!vpn) {
if (bgp->advertise_gw_macip)
return;
bgp->advertise_gw_macip = 1;
bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0);
} else {
if (vpn->advertise_gw_macip)
return;
vpn->advertise_gw_macip = 1;
bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip,
vpn->vni);
}
return;
}
/*
* evpn - disable advertisement of default g/w
*/
static void evpn_unset_advertise_default_gw(struct bgp *bgp,
struct bgpevpn *vpn)
{
if (!vpn) {
if (!bgp->advertise_gw_macip)
return;
bgp->advertise_gw_macip = 0;
bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0);
} else {
if (!vpn->advertise_gw_macip)
return;
vpn->advertise_gw_macip = 0;
bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip,
vpn->vni);
}
return;
}
/* /*
* EVPN (VNI advertisement) enabled. Register with zebra. * EVPN (VNI advertisement) enabled. Register with zebra.
*/ */
@ -1700,6 +1747,9 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn, int *write)
} }
} }
if (vpn->advertise_gw_macip)
vty_out(vty, " advertise-default-gw\n");
vty_out(vty, " exit-vni\n"); vty_out(vty, " exit-vni\n");
} }
} }
@ -1712,6 +1762,77 @@ static void write_vni_config_for_entry(struct hash_backet *backet,
} }
#if defined(HAVE_CUMULUS) #if defined(HAVE_CUMULUS)
DEFUN (bgp_evpn_advertise_default_gw_vni,
bgp_evpn_advertise_default_gw_vni_cmd,
"advertise-default-gw",
"Advertise defualt g/w mac-ip routes in EVPN for a VNI\n")
{
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
if (!bgp)
return CMD_WARNING;
if (!vpn)
return CMD_WARNING;
evpn_set_advertise_default_gw(bgp, vpn);
return CMD_SUCCESS;
}
DEFUN (no_bgp_evpn_advertise_default_vni_gw,
no_bgp_evpn_advertise_default_gw_vni_cmd,
"no advertise-default-gw",
NO_STR
"Withdraw default g/w mac-ip routes from EVPN for a VNI\n")
{
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn);
if (!bgp)
return CMD_WARNING;
if (!vpn)
return CMD_WARNING;
evpn_unset_advertise_default_gw(bgp, vpn);
return CMD_SUCCESS;
}
DEFUN (bgp_evpn_advertise_default_gw,
bgp_evpn_advertise_default_gw_cmd,
"advertise-default-gw",
"Advertise All defualt g/w mac-ip routes in EVPN\n")
{
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
if (!bgp)
return CMD_WARNING;
evpn_set_advertise_default_gw(bgp, NULL);
return CMD_SUCCESS;
}
DEFUN (no_bgp_evpn_advertise_default_gw,
no_bgp_evpn_advertise_default_gw_cmd,
"no advertise-default-gw",
NO_STR
"Withdraw All default g/w mac-ip routes from EVPN\n")
{
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
if (!bgp)
return CMD_WARNING;
evpn_unset_advertise_default_gw(bgp, NULL);
return CMD_SUCCESS;
}
DEFUN (bgp_evpn_advertise_all_vni, DEFUN (bgp_evpn_advertise_all_vni,
bgp_evpn_advertise_all_vni_cmd, bgp_evpn_advertise_all_vni_cmd,
"advertise-all-vni", "advertise-all-vni",
@ -1739,86 +1860,95 @@ DEFUN (no_bgp_evpn_advertise_all_vni,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_bgp_evpn_vni, /*
show_bgp_evpn_vni_cmd, * Display VNI information - for all or a specific VNI
"show bgp evpn vni", */
DEFUN (show_bgp_l2vpn_evpn_vni,
show_bgp_l2vpn_evpn_vni_cmd,
"show bgp l2vpn evpn vni [(1-16777215)]",
SHOW_STR SHOW_STR
BGP_STR BGP_STR
L2VPN_HELP_STR
EVPN_HELP_STR EVPN_HELP_STR
"Show VNI\n")
{
struct bgp *bgp;
bgp = bgp_get_default();
if (!bgp)
return CMD_WARNING;
vty_out(vty, "Advertise All VNI flag: %s\n",
bgp->advertise_all_vni ? "Enabled" : "Disabled");
evpn_show_all_vnis(vty, bgp);
return CMD_SUCCESS;
}
DEFUN (show_bgp_evpn_vni_num,
show_bgp_evpn_vni_num_cmd,
"show bgp evpn vni (1-16777215)",
SHOW_STR
BGP_STR
"Address family modifier\n"
"Show VNI\n" "Show VNI\n"
"VNI number\n") "VNI number\n")
{ {
vni_t vni;
struct bgp *bgp; struct bgp *bgp;
vni_t vni;
int idx = 0;
bgp = bgp_get_default(); bgp = bgp_get_default();
if (!bgp) if (!bgp)
return CMD_WARNING; return CMD_WARNING;
vni = strtoul(argv[4]->arg, NULL, 10); if (!argv_find(argv, argc, "evpn", &idx))
return CMD_WARNING;
if (argc == ((idx + 1) + 1)) {
vty_out(vty, "Advertise gateway macip flag: %s\n",
bgp->advertise_gw_macip ? "Enabled" : "Disabled");
/* Display all VNIs */
vty_out(vty, "Advertise All VNI flag: %s\n",
bgp->advertise_all_vni ? "Enabled" : "Disabled");
evpn_show_all_vnis(vty, bgp);
} else {
/* Display specific VNI */
vni = strtoul(argv[argc - 1]->arg, NULL, 10);
evpn_show_vni(vty, bgp, vni);
}
evpn_show_vni(vty, bgp, vni);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
/* `show bgp evpn summary' commands. */ /*
DEFUN (show_bgp_evpn_summary, * Display EVPN neighbor summary.
show_bgp_evpn_summary_cmd, */
"show bgp evpn summary [json]", DEFUN (show_bgp_l2vpn_evpn_summary,
show_bgp_l2vpn_evpn_summary_cmd,
"show bgp l2vpn evpn summary [json]",
SHOW_STR SHOW_STR
BGP_STR BGP_STR
"EVPN\n" L2VPN_HELP_STR
EVPN_HELP_STR
"Summary of BGP neighbor status\n" "Summary of BGP neighbor status\n"
"JavaScript Object Notation\n") JSON_STR)
{ {
u_char uj = use_json(argc, argv); u_char uj = use_json(argc, argv);
return bgp_show_summary_vty(vty, NULL, AFI_L2VPN, SAFI_EVPN, uj); return bgp_show_summary_vty(vty, NULL, AFI_L2VPN, SAFI_EVPN, uj);
} }
/* Show bgp evpn route */ /*
DEFUN (show_bgp_evpn_route, * Display global EVPN routing table.
show_bgp_evpn_route_cmd, */
"show bgp evpn route [type <macip|multicast>]", DEFUN (show_bgp_l2vpn_evpn_route,
show_bgp_l2vpn_evpn_route_cmd,
"show bgp l2vpn evpn route [type <macip|multicast>]",
SHOW_STR SHOW_STR
BGP_STR BGP_STR
"Address Family Modifier\n" L2VPN_HELP_STR
"Display EVPN route information\n" EVPN_HELP_STR
"EVPN route information\n"
"Specify Route type\n" "Specify Route type\n"
"MAC-IP (Type-2) route\n" "MAC-IP (Type-2) route\n"
"Multicast (Type-3) route\n") "Multicast (Type-3) route\n")
{ {
struct bgp *bgp; struct bgp *bgp;
int idx = 0;
int type = 0; int type = 0;
bgp = bgp_get_default(); bgp = bgp_get_default();
if (!bgp) if (!bgp)
return CMD_WARNING; return CMD_WARNING;
if (argc == 6) { if (!argv_find(argv, argc, "evpn", &idx))
if (strncmp(argv[5]->arg, "ma", 2) == 0) return CMD_WARNING;
if (argc == ((idx + 1) + 3)) {
/* Specific type is requested */
if (strncmp(argv[argc - 1]->arg, "ma", 2) == 0)
type = BGP_EVPN_MAC_IP_ROUTE; type = BGP_EVPN_MAC_IP_ROUTE;
else if (strncmp(argv[5]->arg, "mu", 2) == 0) else if (strncmp(argv[argc - 1]->arg, "mu", 2) == 0)
type = BGP_EVPN_IMET_ROUTE; type = BGP_EVPN_IMET_ROUTE;
else else
return CMD_WARNING; return CMD_WARNING;
@ -1828,13 +1958,17 @@ DEFUN (show_bgp_evpn_route,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_bgp_evpn_route_rd, /*
show_bgp_evpn_route_rd_cmd, * Display global EVPN routing table for specific RD.
"show bgp evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>]", */
DEFUN (show_bgp_l2vpn_evpn_route_rd,
show_bgp_l2vpn_evpn_route_rd_cmd,
"show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>]",
SHOW_STR SHOW_STR
BGP_STR BGP_STR
"Address Family Modifier\n" L2VPN_HELP_STR
"Display EVPN route information\n" EVPN_HELP_STR
"EVPN route information\n"
"Route Distinguisher\n" "Route Distinguisher\n"
"ASN:XX or A.B.C.D:XX\n" "ASN:XX or A.B.C.D:XX\n"
"Specify Route type\n" "Specify Route type\n"
@ -1844,22 +1978,27 @@ DEFUN (show_bgp_evpn_route_rd,
struct bgp *bgp; struct bgp *bgp;
int ret; int ret;
struct prefix_rd prd; struct prefix_rd prd;
int idx = 0;
int type = 0; int type = 0;
bgp = bgp_get_default(); bgp = bgp_get_default();
if (!bgp) if (!bgp)
return CMD_WARNING; return CMD_WARNING;
ret = str2prefix_rd(argv[5]->arg, &prd); if (!argv_find(argv, argc, "evpn", &idx))
return CMD_WARNING;
ret = str2prefix_rd(argv[idx + 3]->arg, &prd);
if (!ret) { if (!ret) {
vty_out(vty, "%% Malformed Route Distinguisher\n"); vty_out(vty, "%% Malformed Route Distinguisher\n");
return CMD_WARNING; return CMD_WARNING;
} }
if (argc == 8) { if (argc == ((idx + 1) + 5)) {
if (strncmp(argv[7]->arg, "ma", 2) == 0) /* Specific type is requested */
if (strncmp(argv[argc - 1]->arg, "ma", 2) == 0)
type = BGP_EVPN_MAC_IP_ROUTE; type = BGP_EVPN_MAC_IP_ROUTE;
else if (strncmp(argv[7]->arg, "mu", 2) == 0) else if (strncmp(argv[argc - 1]->arg, "mu", 2) == 0)
type = BGP_EVPN_IMET_ROUTE; type = BGP_EVPN_IMET_ROUTE;
else else
return CMD_WARNING; return CMD_WARNING;
@ -1869,13 +2008,17 @@ DEFUN (show_bgp_evpn_route_rd,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_bgp_evpn_route_rd_macip, /*
show_bgp_evpn_route_rd_macip_cmd, * Display global EVPN routing table for specific RD and MACIP.
"show bgp evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]", */
DEFUN (show_bgp_l2vpn_evpn_route_rd_macip,
show_bgp_l2vpn_evpn_route_rd_macip_cmd,
"show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]",
SHOW_STR SHOW_STR
BGP_STR BGP_STR
"Address Family Modifier\n" L2VPN_HELP_STR
"Display EVPN route information\n" EVPN_HELP_STR
"EVPN route information\n"
"Route Distinguisher\n" "Route Distinguisher\n"
"ASN:XX or A.B.C.D:XX\n" "ASN:XX or A.B.C.D:XX\n"
"MAC\n" "MAC\n"
@ -1888,23 +2031,28 @@ DEFUN (show_bgp_evpn_route_rd_macip,
struct prefix_rd prd; struct prefix_rd prd;
struct ethaddr mac; struct ethaddr mac;
struct ipaddr ip; struct ipaddr ip;
int idx = 0;
bgp = bgp_get_default(); bgp = bgp_get_default();
if (!bgp) if (!bgp)
return CMD_WARNING; return CMD_WARNING;
ret = str2prefix_rd(argv[5]->arg, &prd); if (!argv_find(argv, argc, "evpn", &idx))
return CMD_WARNING;
ret = str2prefix_rd(argv[idx + 3]->arg, &prd);
if (!ret) { if (!ret) {
vty_out(vty, "%% Malformed Route Distinguisher\n"); vty_out(vty, "%% Malformed Route Distinguisher\n");
return CMD_WARNING; return CMD_WARNING;
} }
if (!prefix_str2mac(argv[7]->arg, &mac)) { if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) {
vty_out(vty, "%% Malformed MAC address\n"); vty_out(vty, "%% Malformed MAC address\n");
return CMD_WARNING; return CMD_WARNING;
} }
memset(&ip, 0, sizeof(ip)); memset(&ip, 0, sizeof(ip));
if (argc == 10 && argv[9]->arg != NULL) { if (argc == (idx + 1 + 7) && argv[argc - 1]->arg != NULL) {
if (str2ipaddr(argv[9]->arg, &ip) != 0) { /* Specific MAC+IP requested */
if (str2ipaddr(argv[argc - 1]->arg, &ip) != 0) {
vty_out(vty, "%% Malformed IP address\n"); vty_out(vty, "%% Malformed IP address\n");
return CMD_WARNING; return CMD_WARNING;
} }
@ -1914,13 +2062,17 @@ DEFUN (show_bgp_evpn_route_rd_macip,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_bgp_evpn_route_vni, /*
show_bgp_evpn_route_vni_cmd, * Display per-VNI EVPN routing table.
"show bgp evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>]", */
DEFUN (show_bgp_l2vpn_evpn_route_vni,
show_bgp_l2vpn_evpn_route_vni_cmd,
"show bgp l2vpn evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>]",
SHOW_STR SHOW_STR
BGP_STR BGP_STR
"Address Family Modifier\n" L2VPN_HELP_STR
"Display EVPN route information\n" EVPN_HELP_STR
"EVPN route information\n"
"VXLAN Network Identifier\n" "VXLAN Network Identifier\n"
"VNI number\n" "VNI number\n"
"Specify Route type\n" "Specify Route type\n"
@ -1933,25 +2085,29 @@ DEFUN (show_bgp_evpn_route_vni,
struct bgp *bgp; struct bgp *bgp;
struct in_addr vtep_ip; struct in_addr vtep_ip;
int type = 0; int type = 0;
int idx = 0;
bgp = bgp_get_default(); bgp = bgp_get_default();
if (!bgp) if (!bgp)
return CMD_WARNING; return CMD_WARNING;
if (!argv_find(argv, argc, "evpn", &idx))
return CMD_WARNING;
vtep_ip.s_addr = 0; vtep_ip.s_addr = 0;
vni = strtoul(argv[5]->arg, NULL, 10); vni = strtoul(argv[idx + 3]->arg, NULL, 10);
if (argc == 8 && argv[6]->arg) { if (argc == (idx + 1 + 5) && argv[idx + 4]->arg) {
if (strncmp(argv[6]->arg, "type", 4) == 0) { if (strncmp(argv[idx + 4]->arg, "type", 4) == 0) {
if (strncmp(argv[7]->arg, "ma", 2) == 0) if (strncmp(argv[idx + 5]->arg, "ma", 2) == 0)
type = BGP_EVPN_MAC_IP_ROUTE; type = BGP_EVPN_MAC_IP_ROUTE;
else if (strncmp(argv[7]->arg, "mu", 2) == 0) else if (strncmp(argv[idx + 5]->arg, "mu", 2) == 0)
type = BGP_EVPN_IMET_ROUTE; type = BGP_EVPN_IMET_ROUTE;
else else
return CMD_WARNING; return CMD_WARNING;
} else if (strncmp(argv[6]->arg, "vtep", 4) == 0) { } else if (strncmp(argv[idx + 4]->arg, "vtep", 4) == 0) {
if (!inet_aton(argv[7]->arg, &vtep_ip)) { if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) {
vty_out(vty, "%% Malformed VTEP IP address\n"); vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING; return CMD_WARNING;
} }
@ -1963,13 +2119,17 @@ DEFUN (show_bgp_evpn_route_vni,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_bgp_evpn_route_vni_macip, /*
show_bgp_evpn_route_vni_macip_cmd, * Display per-VNI EVPN routing table for specific MACIP.
"show bgp evpn route vni (1-16777215) mac WORD [ip WORD]", */
DEFUN (show_bgp_l2vpn_evpn_route_vni_macip,
show_bgp_l2vpn_evpn_route_vni_macip_cmd,
"show bgp l2vpn evpn route vni (1-16777215) mac WORD [ip WORD]",
SHOW_STR SHOW_STR
BGP_STR BGP_STR
"Address Family Modifier\n" L2VPN_HELP_STR
"Display EVPN route information\n" EVPN_HELP_STR
"EVPN route information\n"
"VXLAN Network Identifier\n" "VXLAN Network Identifier\n"
"VNI number\n" "VNI number\n"
"MAC\n" "MAC\n"
@ -1981,19 +2141,23 @@ DEFUN (show_bgp_evpn_route_vni_macip,
struct bgp *bgp; struct bgp *bgp;
struct ethaddr mac; struct ethaddr mac;
struct ipaddr ip; struct ipaddr ip;
int idx = 0;
bgp = bgp_get_default(); bgp = bgp_get_default();
if (!bgp) if (!bgp)
return CMD_WARNING; return CMD_WARNING;
vni = strtoul(argv[5]->arg, NULL, 10); if (!argv_find(argv, argc, "evpn", &idx))
if (!prefix_str2mac(argv[7]->arg, &mac)) { return CMD_WARNING;
vni = strtoul(argv[idx + 3]->arg, NULL, 10);
if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) {
vty_out(vty, "%% Malformed MAC address\n"); vty_out(vty, "%% Malformed MAC address\n");
return CMD_WARNING; return CMD_WARNING;
} }
memset(&ip, 0, sizeof(ip)); memset(&ip, 0, sizeof(ip));
if (argc == 10 && argv[9]->arg != NULL) { if (argc == (idx + 1 + 7) && argv[idx + 7]->arg != NULL) {
if (str2ipaddr(argv[9]->arg, &ip) != 0) { if (str2ipaddr(argv[idx + 7]->arg, &ip) != 0) {
vty_out(vty, "%% Malformed IP address\n"); vty_out(vty, "%% Malformed IP address\n");
return CMD_WARNING; return CMD_WARNING;
} }
@ -2003,13 +2167,17 @@ DEFUN (show_bgp_evpn_route_vni_macip,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_bgp_evpn_route_vni_multicast, /*
show_bgp_evpn_route_vni_multicast_cmd, * Display per-VNI EVPN routing table for specific multicast IP (remote VTEP).
"show bgp evpn route vni (1-16777215) multicast A.B.C.D", */
DEFUN (show_bgp_l2vpn_evpn_route_vni_multicast,
show_bgp_l2vpn_evpn_route_vni_multicast_cmd,
"show bgp l2vpn evpn route vni (1-16777215) multicast A.B.C.D",
SHOW_STR SHOW_STR
BGP_STR BGP_STR
"Address Family Modifier\n" L2VPN_HELP_STR
"Display EVPN route information\n" EVPN_HELP_STR
"EVPN route information\n"
"VXLAN Network Identifier\n" "VXLAN Network Identifier\n"
"VNI number\n" "VNI number\n"
"Multicast (Type-3) route\n" "Multicast (Type-3) route\n"
@ -2019,13 +2187,17 @@ DEFUN (show_bgp_evpn_route_vni_multicast,
struct bgp *bgp; struct bgp *bgp;
int ret; int ret;
struct in_addr orig_ip; struct in_addr orig_ip;
int idx = 0;
bgp = bgp_get_default(); bgp = bgp_get_default();
if (!bgp) if (!bgp)
return CMD_WARNING; return CMD_WARNING;
vni = strtoul(argv[5]->arg, NULL, 10); if (!argv_find(argv, argc, "evpn", &idx))
ret = inet_aton(argv[7]->arg, &orig_ip); return CMD_WARNING;
vni = strtoul(argv[idx + 3]->arg, NULL, 10);
ret = inet_aton(argv[idx + 5]->arg, &orig_ip);
if (!ret) { if (!ret) {
vty_out(vty, "%% Malformed Originating Router IP address\n"); vty_out(vty, "%% Malformed Originating Router IP address\n");
return CMD_WARNING; return CMD_WARNING;
@ -2035,13 +2207,17 @@ DEFUN (show_bgp_evpn_route_vni_multicast,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_bgp_evpn_route_vni_all, /*
show_bgp_evpn_route_vni_all_cmd, * Display per-VNI EVPN routing table - for all VNIs.
"show bgp evpn route vni all [vtep A.B.C.D]", */
DEFUN (show_bgp_l2vpn_evpn_route_vni_all,
show_bgp_l2vpn_evpn_route_vni_all_cmd,
"show bgp l2vpn evpn route vni all [vtep A.B.C.D]",
SHOW_STR SHOW_STR
BGP_STR BGP_STR
"Address Family Modifier\n" L2VPN_HELP_STR
"Display EVPN route information\n" EVPN_HELP_STR
"EVPN route information\n"
"VXLAN Network Identifier\n" "VXLAN Network Identifier\n"
"All VNIs\n" "All VNIs\n"
"Remote VTEP\n" "Remote VTEP\n"
@ -2049,14 +2225,18 @@ DEFUN (show_bgp_evpn_route_vni_all,
{ {
struct bgp *bgp; struct bgp *bgp;
struct in_addr vtep_ip; struct in_addr vtep_ip;
int idx = 0;
bgp = bgp_get_default(); bgp = bgp_get_default();
if (!bgp) if (!bgp)
return CMD_WARNING; return CMD_WARNING;
if (!argv_find(argv, argc, "evpn", &idx))
return CMD_WARNING;
vtep_ip.s_addr = 0; vtep_ip.s_addr = 0;
if (argc == 8 && argv[7]->arg) { if (argc == (idx + 1 + 5) && argv[idx + 5]->arg) {
if (!inet_aton(argv[7]->arg, &vtep_ip)) { if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) {
vty_out(vty, "%% Malformed VTEP IP address\n"); vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING; return CMD_WARNING;
} }
@ -2066,12 +2246,16 @@ DEFUN (show_bgp_evpn_route_vni_all,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_bgp_evpn_import_rt, /*
show_bgp_evpn_import_rt_cmd, * Display EVPN import route-target hash table
"show bgp evpn import-rt", */
DEFUN (show_bgp_l2vpn_evpn_import_rt,
show_bgp_l2vpn_evpn_import_rt_cmd,
"show bgp l2vpn evpn import-rt",
SHOW_STR SHOW_STR
BGP_STR BGP_STR
"Address family modifier\n" L2VPN_HELP_STR
EVPN_HELP_STR
"Show import route target\n") "Show import route target\n")
{ {
struct bgp *bgp; struct bgp *bgp;
@ -2084,6 +2268,97 @@ DEFUN (show_bgp_evpn_import_rt,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
#if defined(HAVE_CUMULUS)
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_vni, show_bgp_evpn_vni_cmd,
"show bgp evpn vni [(1-16777215)]", SHOW_STR BGP_STR EVPN_HELP_STR
"Show VNI\n"
"VNI number\n")
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_summary, show_bgp_evpn_summary_cmd,
"show bgp evpn summary [json]", SHOW_STR BGP_STR EVPN_HELP_STR
"Summary of BGP neighbor status\n"
JSON_STR)
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route, show_bgp_evpn_route_cmd,
"show bgp evpn route [type <macip|multicast>]",
SHOW_STR BGP_STR EVPN_HELP_STR
"EVPN route information\n"
"Specify Route type\n"
"MAC-IP (Type-2) route\n"
"Multicast (Type-3) route\n")
ALIAS_HIDDEN(
show_bgp_l2vpn_evpn_route_rd, show_bgp_evpn_route_rd_cmd,
"show bgp evpn route rd ASN:nn_or_IP-address:nn [type <macip|multicast>]",
SHOW_STR BGP_STR EVPN_HELP_STR
"EVPN route information\n"
"Route Distinguisher\n"
"ASN:XX or A.B.C.D:XX\n"
"Specify Route type\n"
"MAC-IP (Type-2) route\n"
"Multicast (Type-3) route\n")
ALIAS_HIDDEN(
show_bgp_l2vpn_evpn_route_rd_macip, show_bgp_evpn_route_rd_macip_cmd,
"show bgp evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]",
SHOW_STR BGP_STR EVPN_HELP_STR
"EVPN route information\n"
"Route Distinguisher\n"
"ASN:XX or A.B.C.D:XX\n"
"MAC\n"
"MAC address (e.g., 00:e0:ec:20:12:62)\n"
"IP\n"
"IP address (IPv4 or IPv6)\n")
ALIAS_HIDDEN(
show_bgp_l2vpn_evpn_route_vni, show_bgp_evpn_route_vni_cmd,
"show bgp evpn route vni (1-16777215) [<type <macip|multicast> | vtep A.B.C.D>]",
SHOW_STR BGP_STR EVPN_HELP_STR
"EVPN route information\n"
"VXLAN Network Identifier\n"
"VNI number\n"
"Specify Route type\n"
"MAC-IP (Type-2) route\n"
"Multicast (Type-3) route\n"
"Remote VTEP\n"
"Remote VTEP IP address\n")
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_macip,
show_bgp_evpn_route_vni_macip_cmd,
"show bgp evpn route vni (1-16777215) mac WORD [ip WORD]",
SHOW_STR BGP_STR EVPN_HELP_STR
"EVPN route information\n"
"VXLAN Network Identifier\n"
"VNI number\n"
"MAC\n"
"MAC address (e.g., 00:e0:ec:20:12:62)\n"
"IP\n"
"IP address (IPv4 or IPv6)\n")
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_multicast,
show_bgp_evpn_route_vni_multicast_cmd,
"show bgp evpn route vni (1-16777215) multicast A.B.C.D",
SHOW_STR BGP_STR EVPN_HELP_STR
"EVPN route information\n"
"VXLAN Network Identifier\n"
"VNI number\n"
"Multicast (Type-3) route\n"
"Originating Router IP address\n")
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_all, show_bgp_evpn_route_vni_all_cmd,
"show bgp evpn route vni all [vtep A.B.C.D]",
SHOW_STR BGP_STR EVPN_HELP_STR
"EVPN route information\n"
"VXLAN Network Identifier\n"
"All VNIs\n"
"Remote VTEP\n"
"Remote VTEP IP address\n")
ALIAS_HIDDEN(show_bgp_l2vpn_evpn_import_rt, show_bgp_evpn_import_rt_cmd,
"show bgp evpn import-rt",
SHOW_STR BGP_STR EVPN_HELP_STR "Show import route target\n")
#endif
DEFUN_NOSH (bgp_evpn_vni, DEFUN_NOSH (bgp_evpn_vni,
bgp_evpn_vni_cmd, bgp_evpn_vni_cmd,
"vni (1-16777215)", "vni (1-16777215)",
@ -2290,11 +2565,11 @@ DEFUN (bgp_evpn_vni_rt,
if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) { if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) {
ecomadd = ecommunity_str2com(argv[2]->arg, ecomadd = ecommunity_str2com(argv[2]->arg,
ECOMMUNITY_ROUTE_TARGET, 0); ECOMMUNITY_ROUTE_TARGET, 0);
ecommunity_str(ecomadd);
if (!ecomadd) { if (!ecomadd) {
vty_out(vty, "%% Malformed Route Target list\n"); vty_out(vty, "%% Malformed Route Target list\n");
return CMD_WARNING; return CMD_WARNING;
} }
ecommunity_str(ecomadd);
/* Do nothing if we already have this import route-target */ /* Do nothing if we already have this import route-target */
if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomadd)) if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomadd))
@ -2305,11 +2580,11 @@ DEFUN (bgp_evpn_vni_rt,
if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) { if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) {
ecomadd = ecommunity_str2com(argv[2]->arg, ecomadd = ecommunity_str2com(argv[2]->arg,
ECOMMUNITY_ROUTE_TARGET, 0); ECOMMUNITY_ROUTE_TARGET, 0);
ecommunity_str(ecomadd);
if (!ecomadd) { if (!ecomadd) {
vty_out(vty, "%% Malformed Route Target list\n"); vty_out(vty, "%% Malformed Route Target list\n");
return CMD_WARNING; return CMD_WARNING;
} }
ecommunity_str(ecomadd);
/* Do nothing if we already have this export route-target */ /* Do nothing if we already have this export route-target */
if (!bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomadd)) if (!bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomadd))
@ -2372,11 +2647,11 @@ DEFUN (no_bgp_evpn_vni_rt,
} }
ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0); ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0);
ecommunity_str(ecomdel);
if (!ecomdel) { if (!ecomdel) {
vty_out(vty, "%% Malformed Route Target list\n"); vty_out(vty, "%% Malformed Route Target list\n");
return CMD_WARNING; return CMD_WARNING;
} }
ecommunity_str(ecomdel);
if (rt_type == RT_TYPE_IMPORT) { if (rt_type == RT_TYPE_IMPORT) {
if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomdel)) { if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomdel)) {
@ -2484,6 +2759,11 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
bgp_config_write_family_header(vty, afi, safi, write); bgp_config_write_family_header(vty, afi, safi, write);
vty_out(vty, " advertise-all-vni\n"); vty_out(vty, " advertise-all-vni\n");
} }
if (bgp->advertise_gw_macip) {
bgp_config_write_family_header(vty, afi, safi, write);
vty_out(vty, " advertise-default-gw\n");
}
} }
void bgp_ethernetvpn_init(void) void bgp_ethernetvpn_init(void)
@ -2509,10 +2789,24 @@ void bgp_ethernetvpn_init(void)
#if defined(HAVE_CUMULUS) #if defined(HAVE_CUMULUS)
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd);
/* "show bgp l2vpn evpn" commands. */
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_macip_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_cmd);
install_element(VIEW_NODE,
&show_bgp_l2vpn_evpn_route_vni_multicast_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd);
install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd);
/* "show bgp evpn" commands. */ /* "show bgp evpn" commands. */
install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd); install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_vni_num_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_summary_cmd); install_element(VIEW_NODE, &show_bgp_evpn_summary_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_route_cmd); install_element(VIEW_NODE, &show_bgp_evpn_route_cmd);
install_element(VIEW_NODE, &show_bgp_evpn_route_rd_cmd); install_element(VIEW_NODE, &show_bgp_evpn_route_rd_cmd);
@ -2532,5 +2826,9 @@ void bgp_ethernetvpn_init(void)
install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rt_cmd); install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rt_cmd);
install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_cmd); install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_cmd);
install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_without_val_cmd); install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_without_val_cmd);
install_element(BGP_EVPN_VNI_NODE,
&bgp_evpn_advertise_default_gw_vni_cmd);
install_element(BGP_EVPN_VNI_NODE,
&no_bgp_evpn_advertise_default_gw_vni_cmd);
#endif #endif
} }

View File

@ -1580,10 +1580,18 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri,
/* Route map & unsuppress-map apply. */ /* Route map & unsuppress-map apply. */
if (ROUTE_MAP_OUT_NAME(filter) || (ri->extra && ri->extra->suppress)) { if (ROUTE_MAP_OUT_NAME(filter) || (ri->extra && ri->extra->suppress)) {
struct bgp_info info; struct bgp_info info;
struct bgp_info_extra dummy_info_extra;
struct attr dummy_attr; struct attr dummy_attr;
info.peer = peer; info.peer = peer;
info.attr = attr; info.attr = attr;
if (ri->extra) {
memcpy(&dummy_info_extra, ri->extra,
sizeof(struct bgp_info_extra));
info.extra = &dummy_info_extra;
}
/* don't confuse inbound and outbound setting */ /* don't confuse inbound and outbound setting */
RESET_FLAG(attr->rmap_change_flags); RESET_FLAG(attr->rmap_change_flags);
@ -6238,6 +6246,9 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty)
} else } else
len += vty_out(vty, "/%d", p->prefixlen); len += vty_out(vty, "/%d", p->prefixlen);
} else if (p->family == AF_ETHERNET) { } else if (p->family == AF_ETHERNET) {
prefix2str(p, buf, PREFIX_STRLEN);
len = vty_out(vty, "%s", buf);
} else if (p->family == AF_EVPN) {
#if defined(HAVE_CUMULUS) #if defined(HAVE_CUMULUS)
len = vty_out(vty, "%s", len = vty_out(vty, "%s",
bgp_evpn_route2str((struct prefix_evpn *)p, buf, bgp_evpn_route2str((struct prefix_evpn *)p, buf,
@ -6505,15 +6516,14 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
len = vty_out( len = vty_out(
vty, "%s", vty, "%s",
binfo->peer->conf_if); binfo->peer->conf_if);
len = len = 16 - len; /* len of IPv6
7 - len; /* len of IPv6 addr + max
addr + max len of def
len of def ifname */
ifname */
if (len < 1) if (len < 1)
vty_out(vty, "\n%*s", vty_out(vty, "\n%*s",
45, " "); 36, " ");
else else
vty_out(vty, "%*s", len, vty_out(vty, "%*s", len,
" "); " ");
@ -6801,7 +6811,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
if (attr) { if (attr) {
if (((p->family == AF_INET) if (((p->family == AF_INET)
&& ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
|| (safi == SAFI_EVPN && p->family == AF_ETHERNET || (safi == SAFI_EVPN
&& !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) && !BGP_ATTR_NEXTHOP_AFI_IP6(attr))
|| (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
@ -6826,7 +6836,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p,
} }
} else if (((p->family == AF_INET6) } else if (((p->family == AF_INET6)
&& ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP)))
|| (safi == SAFI_EVPN && p->family == AF_ETHERNET || (safi == SAFI_EVPN
&& BGP_ATTR_NEXTHOP_AFI_IP6(attr)) && BGP_ATTR_NEXTHOP_AFI_IP6(attr))
|| (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { || (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
char buf_a[BUFSIZ]; char buf_a[BUFSIZ];
@ -7326,7 +7336,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p,
/* Line2 display Next-hop, Neighbor, Router-id */ /* Line2 display Next-hop, Neighbor, Router-id */
/* Display the nexthop */ /* Display the nexthop */
if ((p->family == AF_INET || p->family == AF_ETHERNET) if ((p->family == AF_INET || p->family == AF_ETHERNET ||
p->family == AF_EVPN)
&& (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP
|| safi == SAFI_EVPN || safi == SAFI_EVPN
|| !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) {
@ -10232,6 +10243,10 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer,
afi_t afi, safi_t safi, afi_t afi, safi_t safi,
enum bgp_show_type type, u_char use_json) enum bgp_show_type type, u_char use_json)
{ {
/* labeled-unicast routes live in the unicast table */
if (safi == SAFI_LABELED_UNICAST)
safi = SAFI_UNICAST;
if (!peer || !peer->afc[afi][safi]) { if (!peer || !peer->afc[afi][safi]) {
if (use_json) { if (use_json) {
json_object *json_no = NULL; json_object *json_no = NULL;

View File

@ -54,6 +54,9 @@
#include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_vty.h" #include "bgpd/bgp_vty.h"
#include "bgpd/bgp_debug.h" #include "bgpd/bgp_debug.h"
#include "bgpd/bgp_evpn.h"
#include "bgpd/bgp_evpn_private.h"
#include "bgpd/bgp_evpn_vty.h"
#if ENABLE_BGP_VNC #if ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h" #include "bgpd/rfapi/bgp_rfapi_cfg.h"
@ -572,6 +575,106 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = {
route_match_ip_route_source_prefix_list_compile, route_match_ip_route_source_prefix_list_compile,
route_match_ip_route_source_prefix_list_free}; route_match_ip_route_source_prefix_list_free};
/* `match mac address MAC_ACCESS_LIST' */
/* Match function should return 1 if match is success else return
zero. */
static route_map_result_t route_match_mac_address(void *rule,
struct prefix *prefix,
route_map_object_t type,
void *object)
{
struct access_list *alist;
struct prefix p;
if (type == RMAP_BGP) {
alist = access_list_lookup(AFI_L2VPN, (char *)rule);
if (alist == NULL)
return RMAP_NOMATCH;
if (prefix->u.prefix_evpn.route_type != BGP_EVPN_MAC_IP_ROUTE)
return RMAP_NOMATCH;
p.family = AF_ETHERNET;
p.prefixlen = ETH_ALEN * 8;
p.u.prefix_eth = prefix->u.prefix_evpn.mac;
return (access_list_apply(alist, &p)
== FILTER_DENY
? RMAP_NOMATCH
: RMAP_MATCH);
}
return RMAP_NOMATCH;
}
/* Route map `mac address' match statement. `arg' should be
access-list name. */
static void *route_match_mac_address_compile(const char *arg)
{
return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
}
/* Free route map's compiled `ip address' value. */
static void route_match_mac_address_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}
/* Route map commands for mac address matching. */
struct route_map_rule_cmd route_match_mac_address_cmd = {
"mac address", route_match_mac_address, route_match_mac_address_compile,
route_match_mac_address_free};
/* `match vni' */
/* Match function should return 1 if match is success else return
zero. */
static route_map_result_t route_match_vni(void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
vni_t vni = 0;
struct bgp_info *bgp_info = NULL;
if (type == RMAP_BGP) {
vni = *((vni_t *)rule);
bgp_info = (struct bgp_info *)object;
if (vni == label2vni(&bgp_info->extra->label))
return RMAP_MATCH;
}
return RMAP_NOMATCH;
}
/* Route map `vni' match statement. */
static void *route_match_vni_compile(const char *arg)
{
vni_t *vni = NULL;
char *end = NULL;
vni = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(vni_t));
if (!vni)
return NULL;
*vni = strtoul(arg, &end, 10);
if (*end != '\0')
return NULL;
return vni;
}
/* Free route map's compiled `vni' value. */
static void route_match_vni_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}
/* Route map commands for vni matching. */
struct route_map_rule_cmd route_match_evpn_vni_cmd = {
"evpn vni", route_match_vni, route_match_vni_compile,
route_match_vni_free};
/* `match local-preference LOCAL-PREF' */ /* `match local-preference LOCAL-PREF' */
/* Match function return 1 if match is success else return zero. */ /* Match function return 1 if match is success else return zero. */
@ -2994,6 +3097,55 @@ static void bgp_route_map_event(route_map_event_t event, const char *rmap_name)
route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED); route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED);
} }
DEFUN (match_mac_address,
match_mac_address_cmd,
"match mac address WORD",
MATCH_STR
"mac address\n"
"Match address of route\n"
"MAC Access-list name\n")
{
return bgp_route_match_add(vty, "mac address", argv[3]->arg,
RMAP_EVENT_FILTER_ADDED);
}
DEFUN (no_match_mac_address,
no_match_mac_address_cmd,
"no match mac address WORD",
NO_STR
MATCH_STR
"mac\n"
"Match address of route\n"
"MAC acess-list name\n")
{
return bgp_route_match_delete(vty, "mac address", argv[4]->arg,
RMAP_EVENT_FILTER_DELETED);
}
DEFUN (match_evpn_vni,
match_evpn_vni_cmd,
"match evpn vni (1-16777215)",
MATCH_STR
EVPN_HELP_STR
"Match VNI\n"
"VNI ID\n")
{
return bgp_route_match_add(vty, "evpn vni", argv[3]->arg,
RMAP_EVENT_MATCH_ADDED);
}
DEFUN (no_match_evpn_vni,
no_match_evpn_vni_cmd,
"no match evpn vni (1-16777215)",
NO_STR
MATCH_STR
EVPN_HELP_STR
"Match VNI\n"
"VNI ID\n")
{
return bgp_route_match_delete(vty, "evpn vni", argv[4]->arg,
RMAP_EVENT_MATCH_DELETED);
}
DEFUN (match_peer, DEFUN (match_peer,
match_peer_cmd, match_peer_cmd,
@ -4351,6 +4503,8 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_probability_cmd); route_map_install_match(&route_match_probability_cmd);
route_map_install_match(&route_match_interface_cmd); route_map_install_match(&route_match_interface_cmd);
route_map_install_match(&route_match_tag_cmd); route_map_install_match(&route_match_tag_cmd);
route_map_install_match(&route_match_mac_address_cmd);
route_map_install_match(&route_match_evpn_vni_cmd);
route_map_install_set(&route_set_ip_nexthop_cmd); route_map_install_set(&route_set_ip_nexthop_cmd);
route_map_install_set(&route_set_local_pref_cmd); route_map_install_set(&route_set_local_pref_cmd);
@ -4381,6 +4535,10 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &no_match_ip_route_source_cmd); install_element(RMAP_NODE, &no_match_ip_route_source_cmd);
install_element(RMAP_NODE, &match_ip_route_source_prefix_list_cmd); install_element(RMAP_NODE, &match_ip_route_source_prefix_list_cmd);
install_element(RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd); install_element(RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd);
install_element(RMAP_NODE, &match_mac_address_cmd);
install_element(RMAP_NODE, &no_match_mac_address_cmd);
install_element(RMAP_NODE, &match_evpn_vni_cmd);
install_element(RMAP_NODE, &no_match_evpn_vni_cmd);
install_element(RMAP_NODE, &match_aspath_cmd); install_element(RMAP_NODE, &match_aspath_cmd);
install_element(RMAP_NODE, &no_match_aspath_cmd); install_element(RMAP_NODE, &no_match_aspath_cmd);

View File

@ -12047,6 +12047,8 @@ void bgp_vty_init(void)
install_element(BGP_VPNV4_NODE, &no_neighbor_route_map_cmd); install_element(BGP_VPNV4_NODE, &no_neighbor_route_map_cmd);
install_element(BGP_VPNV6_NODE, &neighbor_route_map_cmd); install_element(BGP_VPNV6_NODE, &neighbor_route_map_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_route_map_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_route_map_cmd);
install_element(BGP_EVPN_NODE, &neighbor_route_map_cmd);
install_element(BGP_EVPN_NODE, &no_neighbor_route_map_cmd);
/* "neighbor unsuppress-map" commands. */ /* "neighbor unsuppress-map" commands. */
install_element(BGP_NODE, &neighbor_unsuppress_map_hidden_cmd); install_element(BGP_NODE, &neighbor_unsuppress_map_hidden_cmd);

View File

@ -2034,6 +2034,29 @@ void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer)
zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 0, 0); zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 0, 0);
} }
int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni)
{
struct stream *s = NULL;
/* Check socket. */
if (!zclient || zclient->sock < 0)
return 0;
/* Don't try to register if Zebra doesn't know of this instance. */
if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
return 0;
s = zclient->obuf;
stream_reset(s);
zclient_create_header(s, ZEBRA_ADVERTISE_DEFAULT_GW, bgp->vrf_id);
stream_putc(s, advertise);
stream_put3(s, vni);
stream_putw_at(s, 0, stream_get_endp(s));
return zclient_send_message(zclient);
}
int bgp_zebra_advertise_all_vni(struct bgp *bgp, int advertise) int bgp_zebra_advertise_all_vni(struct bgp *bgp, int advertise)
{ {
struct stream *s; struct stream *s;
@ -2120,7 +2143,7 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
int ipa_len; int ipa_len;
char buf[ETHER_ADDR_STRLEN]; char buf[ETHER_ADDR_STRLEN];
char buf1[INET6_ADDRSTRLEN]; char buf1[INET6_ADDRSTRLEN];
u_char sticky; u_char flags;
memset(&ip, 0, sizeof(ip)); memset(&ip, 0, sizeof(ip));
s = zclient->ibuf; s = zclient->ibuf;
@ -2140,21 +2163,20 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
(ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 : IPADDR_V6; (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 : IPADDR_V6;
stream_get(&ip.ip.addr, s, ipa_len); stream_get(&ip.ip.addr, s, ipa_len);
} }
sticky = stream_getc(s); flags = stream_getc(s);
bgp = bgp_lookup_by_vrf_id(vrf_id); bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp) if (!bgp)
return 0; return 0;
if (BGP_DEBUG(zebra, ZEBRA)) if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("%u:Recv MACIP %s %sMAC %s IP %s VNI %u", vrf_id, zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u",
(command == ZEBRA_MACIP_ADD) ? "Add" : "Del", vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
sticky ? "sticky " : "", flags, prefix_mac2str(&mac, buf, sizeof(buf)),
prefix_mac2str(&mac, buf, sizeof(buf)),
ipaddr2str(&ip, buf1, sizeof(buf1)), vni); ipaddr2str(&ip, buf1, sizeof(buf1)), vni);
if (command == ZEBRA_MACIP_ADD) if (command == ZEBRA_MACIP_ADD)
return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, sticky); return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, flags);
else else
return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip); return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip);
} }

View File

@ -21,6 +21,8 @@
#ifndef _QUAGGA_BGP_ZEBRA_H #ifndef _QUAGGA_BGP_ZEBRA_H
#define _QUAGGA_BGP_ZEBRA_H #define _QUAGGA_BGP_ZEBRA_H
#include "vxlan.h"
extern void bgp_zebra_init(struct thread_master *master); extern void bgp_zebra_init(struct thread_master *master);
extern void bgp_zebra_destroy(void); extern void bgp_zebra_destroy(void);
extern int bgp_if_update_all(void); extern int bgp_if_update_all(void);
@ -57,6 +59,7 @@ extern struct interface *if_lookup_by_ipv6(struct in6_addr *, ifindex_t,
extern struct interface *if_lookup_by_ipv6_exact(struct in6_addr *, ifindex_t, extern struct interface *if_lookup_by_ipv6_exact(struct in6_addr *, ifindex_t,
vrf_id_t); vrf_id_t);
extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t);
extern int bgp_zebra_advertise_all_vni(struct bgp *, int); extern int bgp_zebra_advertise_all_vni(struct bgp *, int);
extern int bgp_zebra_num_connects(void); extern int bgp_zebra_num_connects(void);

View File

@ -380,6 +380,9 @@ struct bgp {
/* EVI hash table */ /* EVI hash table */
struct hash *vnihash; struct hash *vnihash;
/* EVPN enable - advertise gateway macip routes */
int advertise_gw_macip;
/* EVPN enable - advertise local VNIs and their MACs etc. */ /* EVPN enable - advertise local VNIs and their MACs etc. */
int advertise_all_vni; int advertise_all_vni;
@ -1488,7 +1491,8 @@ static inline int peer_group_af_configured(struct peer_group *group)
|| peer->afc[AFI_IP6][SAFI_MULTICAST] || peer->afc[AFI_IP6][SAFI_MULTICAST]
|| peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST]
|| peer->afc[AFI_IP6][SAFI_MPLS_VPN] || peer->afc[AFI_IP6][SAFI_MPLS_VPN]
|| peer->afc[AFI_IP6][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_EVPN]) || peer->afc[AFI_IP6][SAFI_ENCAP]
|| peer->afc[AFI_L2VPN][SAFI_EVPN])
return 1; return 1;
return 0; return 0;
} }

View File

@ -21,6 +21,8 @@
#include "command.h" #include "command.h"
#include "vty.h" #include "vty.h"
#include "json.h"
#include "ldpd/ldpd.h" #include "ldpd/ldpd.h"
#include "ldpd/ldp_vty.h" #include "ldpd/ldp_vty.h"
#include "ldpd/ldp_vty_cmds_clippy.c" #include "ldpd/ldp_vty_cmds_clippy.c"
@ -586,7 +588,7 @@ DEFPY (ldp_show_mpls_ldp_binding,
"IPv6 Address Family\n" "IPv6 Address Family\n"
"Label Information Base (LIB) information\n" "Label Information Base (LIB) information\n"
"Show detailed information\n" "Show detailed information\n"
"JavaScript Object Notation\n") JSON_STR)
{ {
return (ldp_vty_show_binding(vty, af, detail, json)); return (ldp_vty_show_binding(vty, af, detail, json));
} }
@ -601,7 +603,7 @@ DEFPY (ldp_show_mpls_ldp_discovery,
"IPv6 Address Family\n" "IPv6 Address Family\n"
"Discovery Hello Information\n" "Discovery Hello Information\n"
"Show detailed information\n" "Show detailed information\n"
"JavaScript Object Notation\n") JSON_STR)
{ {
return (ldp_vty_show_discovery(vty, af, detail, json)); return (ldp_vty_show_discovery(vty, af, detail, json));
} }
@ -615,7 +617,7 @@ DEFPY (ldp_show_mpls_ldp_interface,
"IPv4 Address Family\n" "IPv4 Address Family\n"
"IPv6 Address Family\n" "IPv6 Address Family\n"
"interface information\n" "interface information\n"
"JavaScript Object Notation\n") JSON_STR)
{ {
return (ldp_vty_show_interface(vty, af, json)); return (ldp_vty_show_interface(vty, af, json));
} }
@ -627,7 +629,7 @@ DEFPY (ldp_show_mpls_ldp_capabilities,
"MPLS information\n" "MPLS information\n"
"Label Distribution Protocol\n" "Label Distribution Protocol\n"
"Display LDP Capabilities information\n" "Display LDP Capabilities information\n"
"JavaScript Object Notation\n") JSON_STR)
{ {
return (ldp_vty_show_capabilities(vty, json)); return (ldp_vty_show_capabilities(vty, json));
} }
@ -640,7 +642,7 @@ DEFPY (ldp_show_mpls_ldp_neighbor,
"Label Distribution Protocol\n" "Label Distribution Protocol\n"
"Neighbor information\n" "Neighbor information\n"
"Show detailed information\n" "Show detailed information\n"
"JavaScript Object Notation\n") JSON_STR)
{ {
return (ldp_vty_show_neighbor(vty, 0, detail, json)); return (ldp_vty_show_neighbor(vty, 0, detail, json));
} }
@ -653,7 +655,7 @@ DEFPY (ldp_show_mpls_ldp_neighbor_capabilities,
"Label Distribution Protocol\n" "Label Distribution Protocol\n"
"Neighbor information\n" "Neighbor information\n"
"Display neighbor capability information\n" "Display neighbor capability information\n"
"JavaScript Object Notation\n") JSON_STR)
{ {
return (ldp_vty_show_neighbor(vty, 1, NULL, json)); return (ldp_vty_show_neighbor(vty, 1, NULL, json));
} }
@ -665,7 +667,7 @@ DEFPY (ldp_show_l2vpn_atom_binding,
"Show information about Layer2 VPN\n" "Show information about Layer2 VPN\n"
"Show Any Transport over MPLS information\n" "Show Any Transport over MPLS information\n"
"Show AToM label binding information\n" "Show AToM label binding information\n"
"JavaScript Object Notation\n") JSON_STR)
{ {
return (ldp_vty_show_atom_binding(vty, json)); return (ldp_vty_show_atom_binding(vty, json));
} }
@ -677,7 +679,7 @@ DEFPY (ldp_show_l2vpn_atom_vc,
"Show information about Layer2 VPN\n" "Show information about Layer2 VPN\n"
"Show Any Transport over MPLS information\n" "Show Any Transport over MPLS information\n"
"Show AToM virtual circuit information\n" "Show AToM virtual circuit information\n"
"JavaScript Object Notation\n") JSON_STR)
{ {
return (ldp_vty_show_atom_vc(vty, json)); return (ldp_vty_show_atom_vc(vty, json));
} }

View File

@ -101,6 +101,7 @@ const char *node_names[] = {
"ipv4 access list", // ACCESS_NODE, "ipv4 access list", // ACCESS_NODE,
"ipv4 prefix list", // PREFIX_NODE, "ipv4 prefix list", // PREFIX_NODE,
"ipv6 access list", // ACCESS_IPV6_NODE, "ipv6 access list", // ACCESS_IPV6_NODE,
"MAC access list", // ACCESS_MAC_NODE,
"ipv6 prefix list", // PREFIX_IPV6_NODE, "ipv6 prefix list", // PREFIX_IPV6_NODE,
"as list", // AS_LIST_NODE, "as list", // AS_LIST_NODE,
"community list", // COMMUNITY_LIST_NODE, "community list", // COMMUNITY_LIST_NODE,

View File

@ -123,6 +123,7 @@ enum node_type {
ACCESS_NODE, /* Access list node. */ ACCESS_NODE, /* Access list node. */
PREFIX_NODE, /* Prefix list node. */ PREFIX_NODE, /* Prefix list node. */
ACCESS_IPV6_NODE, /* Access list node. */ ACCESS_IPV6_NODE, /* Access list node. */
ACCESS_MAC_NODE, /* MAC access list node*/
PREFIX_IPV6_NODE, /* Prefix list node. */ PREFIX_IPV6_NODE, /* Prefix list node. */
AS_LIST_NODE, /* AS list node. */ AS_LIST_NODE, /* AS list node. */
COMMUNITY_LIST_NODE, /* Community list node. */ COMMUNITY_LIST_NODE, /* Community list node. */

View File

@ -90,6 +90,14 @@ struct access_master {
void (*delete_hook)(struct access_list *); void (*delete_hook)(struct access_list *);
}; };
/* Static structure for mac access_list's master. */
static struct access_master access_master_mac = {
{NULL, NULL},
{NULL, NULL},
NULL,
NULL,
};
/* Static structure for IPv4 access_list's master. */ /* Static structure for IPv4 access_list's master. */
static struct access_master access_master_ipv4 = { static struct access_master access_master_ipv4 = {
{NULL, NULL}, {NULL, NULL},
@ -112,6 +120,8 @@ static struct access_master *access_master_get(afi_t afi)
return &access_master_ipv4; return &access_master_ipv4;
else if (afi == AFI_IP6) else if (afi == AFI_IP6)
return &access_master_ipv6; return &access_master_ipv6;
else if (afi == AFI_L2VPN)
return &access_master_mac;
return NULL; return NULL;
} }
@ -173,7 +183,7 @@ static int filter_match_cisco(struct filter *mfilter, struct prefix *p)
/* If filter match to the prefix then return 1. */ /* If filter match to the prefix then return 1. */
static int filter_match_zebra(struct filter *mfilter, struct prefix *p) static int filter_match_zebra(struct filter *mfilter, struct prefix *p)
{ {
struct filter_zebra *filter; struct filter_zebra *filter = NULL;
filter = &mfilter->u.zfilter; filter = &mfilter->u.zfilter;
@ -365,9 +375,7 @@ static struct access_list *access_list_get(afi_t afi, const char *name)
enum filter_type access_list_apply(struct access_list *access, void *object) enum filter_type access_list_apply(struct access_list *access, void *object)
{ {
struct filter *filter; struct filter *filter;
struct prefix *p; struct prefix *p = (struct prefix *)object;
p = (struct prefix *)object;
if (access == NULL) if (access == NULL)
return FILTER_DENY; return FILTER_DENY;
@ -390,6 +398,7 @@ void access_list_add_hook(void (*func)(struct access_list *access))
{ {
access_master_ipv4.add_hook = func; access_master_ipv4.add_hook = func;
access_master_ipv6.add_hook = func; access_master_ipv6.add_hook = func;
access_master_mac.add_hook = func;
} }
/* Delete hook function. */ /* Delete hook function. */
@ -397,6 +406,7 @@ void access_list_delete_hook(void (*func)(struct access_list *access))
{ {
access_master_ipv4.delete_hook = func; access_master_ipv4.delete_hook = func;
access_master_ipv6.delete_hook = func; access_master_ipv6.delete_hook = func;
access_master_mac.delete_hook = func;
} }
/* Add new filter to the end of specified access_list. */ /* Add new filter to the end of specified access_list. */
@ -515,10 +525,10 @@ static struct filter *filter_lookup_zebra(struct access_list *access,
filter = &mfilter->u.zfilter; filter = &mfilter->u.zfilter;
if (filter->exact == new->exact if (filter->exact == new->exact
&& mfilter->type && mfilter->type == mnew->type) {
== mnew->type &&prefix_same(&filter->prefix, if (prefix_same(&filter->prefix, &new->prefix))
&new->prefix)) return mfilter;
return mfilter; }
} }
return NULL; return NULL;
} }
@ -1252,6 +1262,12 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
"IPv6 address prefix/prefixlen is malformed\n"); "IPv6 address prefix/prefixlen is malformed\n");
return CMD_WARNING_CONFIG_FAILED; return CMD_WARNING_CONFIG_FAILED;
} }
} else if (afi == AFI_L2VPN) {
ret = str2prefix_eth(prefix_str, (struct prefix_eth *)&p);
if (ret <= 0) {
vty_out(vty, "MAC address is malformed\n");
return CMD_WARNING;
}
} else } else
return CMD_WARNING_CONFIG_FAILED; return CMD_WARNING_CONFIG_FAILED;
@ -1274,7 +1290,6 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
access_list_filter_add(access, mfilter); access_list_filter_add(access, mfilter);
} else { } else {
struct filter *delete_filter; struct filter *delete_filter;
delete_filter = filter_lookup_zebra(access, mfilter); delete_filter = filter_lookup_zebra(access, mfilter);
if (delete_filter) if (delete_filter)
access_list_filter_delete(access, delete_filter); access_list_filter_delete(access, delete_filter);
@ -1285,6 +1300,64 @@ static int filter_set_zebra(struct vty *vty, const char *name_str,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (mac_access_list,
mac_access_list_cmd,
"mac access-list WORD <deny|permit> MAC",
"Add a mac access-list\n"
"Add an access list entry\n"
"MAC zebra access-list name\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN,
argv[4]->arg, 0, 1);
}
DEFUN (no_mac_access_list,
no_mac_access_list_cmd,
"no mac access-list WORD <deny|permit> MAC",
NO_STR
"Remove a mac access-list\n"
"Remove an access list entry\n"
"MAC zebra access-list name\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN,
argv[5]->arg, 0, 0);
}
DEFUN (mac_access_list_any,
mac_access_list_any_cmd,
"mac access-list WORD <deny|permit> any",
"Add a mac access-list\n"
"Add an access list entry\n"
"MAC zebra access-list name\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN,
"00:00:00:00:00:00", 0, 1);
}
DEFUN (no_mac_access_list_any,
no_mac_access_list_any_cmd,
"no mac access-list WORD <deny|permit> any",
NO_STR
"Remove a mac access-list\n"
"Remove an access list entry\n"
"MAC zebra access-list name\n"
"Specify packets to reject\n"
"Specify packets to forward\n"
"MAC address to match. e.g. 00:01:00:01:00:01\n")
{
return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN,
"00:00:00:00:00:00", 0, 0);
}
DEFUN (access_list_exact, DEFUN (access_list_exact,
access_list_exact_cmd, access_list_exact_cmd,
"access-list WORD <deny|permit> A.B.C.D/M [exact-match]", "access-list WORD <deny|permit> A.B.C.D/M [exact-match]",
@ -1666,12 +1739,15 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
filter = &mfilter->u.cfilter; filter = &mfilter->u.cfilter;
if (write) { if (write) {
vty_out(vty, "%s IP%s access list %s\n", vty_out(vty, "%s %s access list %s\n",
mfilter->cisco ? (filter->extended mfilter->cisco ? (filter->extended
? "Extended" ? "Extended"
: "Standard") : "Standard")
: "Zebra", : "Zebra",
afi == AFI_IP6 ? "v6" : "", (afi == AFI_IP)
? ("IP")
: ((afi == AFI_IP6) ? ("IPv6 ")
: ("MAC ")),
access->name); access->name);
write = 0; write = 0;
} }
@ -1710,12 +1786,15 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
filter = &mfilter->u.cfilter; filter = &mfilter->u.cfilter;
if (write) { if (write) {
vty_out(vty, "%s IP%s access list %s\n", vty_out(vty, "%s %s access list %s\n",
mfilter->cisco ? (filter->extended mfilter->cisco ? (filter->extended
? "Extended" ? "Extended"
: "Standard") : "Standard")
: "Zebra", : "Zebra",
afi == AFI_IP6 ? "v6" : "", (afi == AFI_IP)
? ("IP")
: ((afi == AFI_IP6) ? ("IPv6 ")
: ("MAC ")),
access->name); access->name);
write = 0; write = 0;
} }
@ -1746,6 +1825,28 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi)
return CMD_SUCCESS; return CMD_SUCCESS;
} }
/* show MAC access list - this only has MAC filters for now*/
DEFUN (show_mac_access_list,
show_mac_access_list_cmd,
"show mac access-list",
SHOW_STR
"mac access lists\n"
"List mac access lists\n")
{
return filter_show(vty, NULL, AFI_L2VPN);
}
DEFUN (show_mac_access_list_name,
show_mac_access_list_name_cmd,
"show mac access-list WORD",
SHOW_STR
"mac access lists\n"
"List mac access lists\n"
"mac address\n")
{
return filter_show(vty, argv[3]->arg, AFI_L2VPN);
}
DEFUN (show_ip_access_list, DEFUN (show_ip_access_list,
show_ip_access_list_cmd, show_ip_access_list_cmd,
"show ip access-list", "show ip access-list",
@ -1844,10 +1945,17 @@ void config_write_access_zebra(struct vty *vty, struct filter *mfilter)
if (p->prefixlen == 0 && !filter->exact) if (p->prefixlen == 0 && !filter->exact)
vty_out(vty, " any"); vty_out(vty, " any");
else else if (p->family == AF_INET6 || p->family == AF_INET)
vty_out(vty, " %s/%d%s", vty_out(vty, " %s/%d%s",
inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
p->prefixlen, filter->exact ? " exact-match" : ""); p->prefixlen, filter->exact ? " exact-match" : "");
else if (p->family == AF_ETHERNET) {
if (p->prefixlen == 0)
vty_out(vty, " any");
else
vty_out(vty, " %s", prefix_mac2str(&(p->u.prefix_eth),
buf, sizeof(buf)));
}
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
@ -1866,15 +1974,19 @@ static int config_write_access(struct vty *vty, afi_t afi)
for (access = master->num.head; access; access = access->next) { for (access = master->num.head; access; access = access->next) {
if (access->remark) { if (access->remark) {
vty_out(vty, "%saccess-list %s remark %s\n", vty_out(vty, "%saccess-list %s remark %s\n",
afi == AFI_IP ? "" : "ipv6 ", access->name, (afi == AFI_IP) ? ("")
access->remark); : ((afi == AFI_IP6) ? ("ipv6 ")
: ("mac ")),
access->name, access->remark);
write++; write++;
} }
for (mfilter = access->head; mfilter; mfilter = mfilter->next) { for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
vty_out(vty, "%saccess-list %s %s", vty_out(vty, "%saccess-list %s %s",
afi == AFI_IP ? "" : "ipv6 ", access->name, (afi == AFI_IP) ? ("")
filter_type_str(mfilter)); : ((afi == AFI_IP6) ? ("ipv6 ")
: ("mac ")),
access->name, filter_type_str(mfilter));
if (mfilter->cisco) if (mfilter->cisco)
config_write_access_cisco(vty, mfilter); config_write_access_cisco(vty, mfilter);
@ -1888,15 +2000,19 @@ static int config_write_access(struct vty *vty, afi_t afi)
for (access = master->str.head; access; access = access->next) { for (access = master->str.head; access; access = access->next) {
if (access->remark) { if (access->remark) {
vty_out(vty, "%saccess-list %s remark %s\n", vty_out(vty, "%saccess-list %s remark %s\n",
afi == AFI_IP ? "" : "ipv6 ", access->name, (afi == AFI_IP) ? ("")
access->remark); : ((afi == AFI_IP6) ? ("ipv6 ")
: ("mac ")),
access->name, access->remark);
write++; write++;
} }
for (mfilter = access->head; mfilter; mfilter = mfilter->next) { for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
vty_out(vty, "%saccess-list %s %s", vty_out(vty, "%saccess-list %s %s",
afi == AFI_IP ? "" : "ipv6 ", access->name, (afi == AFI_IP) ? ("")
filter_type_str(mfilter)); : ((afi == AFI_IP6) ? ("ipv6 ")
: ("mac ")),
access->name, filter_type_str(mfilter));
if (mfilter->cisco) if (mfilter->cisco)
config_write_access_cisco(vty, mfilter); config_write_access_cisco(vty, mfilter);
@ -1909,6 +2025,56 @@ static int config_write_access(struct vty *vty, afi_t afi)
return write; return write;
} }
static struct cmd_node access_mac_node = {
ACCESS_MAC_NODE, "", /* Access list has no interface. */
1};
static int config_write_access_mac(struct vty *vty)
{
return config_write_access(vty, AFI_L2VPN);
}
static void access_list_reset_mac(void)
{
struct access_list *access;
struct access_list *next;
struct access_master *master;
master = access_master_get(AFI_L2VPN);
if (master == NULL)
return;
for (access = master->num.head; access; access = next) {
next = access->next;
access_list_delete(access);
}
for (access = master->str.head; access; access = next) {
next = access->next;
access_list_delete(access);
}
assert(master->num.head == NULL);
assert(master->num.tail == NULL);
assert(master->str.head == NULL);
assert(master->str.tail == NULL);
}
/* Install vty related command. */
static void access_list_init_mac(void)
{
install_node(&access_mac_node, config_write_access_mac);
install_element(ENABLE_NODE, &show_mac_access_list_cmd);
install_element(ENABLE_NODE, &show_mac_access_list_name_cmd);
/* Zebra access-list */
install_element(CONFIG_NODE, &mac_access_list_cmd);
install_element(CONFIG_NODE, &no_mac_access_list_cmd);
install_element(CONFIG_NODE, &mac_access_list_any_cmd);
install_element(CONFIG_NODE, &no_mac_access_list_any_cmd);
}
/* Access-list node. */ /* Access-list node. */
static struct cmd_node access_node = {ACCESS_NODE, static struct cmd_node access_node = {ACCESS_NODE,
"", /* Access list has no interface. */ "", /* Access list has no interface. */
@ -2050,10 +2216,12 @@ void access_list_init()
{ {
access_list_init_ipv4(); access_list_init_ipv4();
access_list_init_ipv6(); access_list_init_ipv6();
access_list_init_mac();
} }
void access_list_reset() void access_list_reset()
{ {
access_list_reset_ipv4(); access_list_reset_ipv4();
access_list_reset_ipv6(); access_list_reset_ipv6();
access_list_reset_mac();
} }

View File

@ -917,6 +917,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK), DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK),
DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK), DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK),
DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI), DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI),
DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW),
DESC_ENTRY(ZEBRA_VNI_ADD), DESC_ENTRY(ZEBRA_VNI_ADD),
DESC_ENTRY(ZEBRA_VNI_DEL), DESC_ENTRY(ZEBRA_VNI_DEL),
DESC_ENTRY(ZEBRA_REMOTE_VTEP_ADD), DESC_ENTRY(ZEBRA_REMOTE_VTEP_ADD),

View File

@ -37,390 +37,262 @@ static const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
static const struct in6_addr maskbytes6[] = { static const struct in6_addr maskbytes6[] = {
/* /0 */ {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /0 */ {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /1 */ /* /1 */ {{{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
{{{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /2 */ {{{0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* /2 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /3 */ {{{0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /3 */ /* /4 */ {{{0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
{{{0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /5 */ {{{0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* /4 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /6 */ {{{0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /5 */ /* /7 */ {{{0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
{{{0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /8 */ {{{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* /6 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /9 */ {{{0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /7 */ /* /10 */ {{{0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
{{{0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /11 */ {{{0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* /8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /12 */ {{{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /9 */ /* /13 */ {{{0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
{{{0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /14 */ {{{0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* /10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /15 */ {{{0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /11 */ /* /16 */ {{{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
{{{0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /17 */ {{{0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* /12 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /18 */ {{{0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /13 */ /* /19 */ {{{0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
{{{0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /20 */ {{{0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* /14 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /21 */ {{{0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /15 */ /* /22 */ {{{0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
{{{0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /23 */ {{{0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* /16 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /24 */ {{{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /17 */ /* /25 */ {{{0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
{{{0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /26 */ {{{0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00,
/* /18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /27 */ {{{0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /19 */ /* /28 */ {{{0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
{{{0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /29 */ {{{0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
/* /20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /30 */ {{{0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /21 */ /* /31 */ {{{0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
{{{0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /32 */ {{{0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
/* /22 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /33 */ {{{0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /23 */ /* /34 */ {{{0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00,
{{{0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /35 */ {{{0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00,
/* /24 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /36 */ {{{0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /25 */ /* /37 */ {{{0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00,
{{{0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /38 */ {{{0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00,
/* /26 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /39 */ {{{0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /27 */ /* /40 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
{{{0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /41 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00,
/* /28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /42 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /29 */ /* /43 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00,
{{{0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /44 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00,
/* /30 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /45 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /31 */ /* /46 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00,
{{{0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /47 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00,
/* /32 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /48 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /33 */ /* /49 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00,
{{{0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /50 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00,
/* /34 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /51 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /35 */ /* /52 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00,
{{{0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /53 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00,
/* /36 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /54 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /37 */ /* /55 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00,
{{{0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /56 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00,
/* /38 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /57 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /39 */ /* /58 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00,
{{{0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /59 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00,
/* /40 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* /60 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /41 */ /* /61 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /62 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00,
/* /42 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, /* /63 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /43 */ /* /64 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /65 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80,
/* /44 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, /* /66 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /45 */ /* /67 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /68 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0,
/* /46 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, /* /69 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /47 */ /* /70 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /71 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
/* /48 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, /* /72 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /49 */ /* /73 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /74 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /50 */ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, /* /75 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /51 */ /* /76 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /77 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /52 */ 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, /* /78 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /53 */ /* /79 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /80 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /54 */ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, /* /81 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /55 */ /* /82 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /83 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /56 */ 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, /* /84 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /57 */ /* /85 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /86 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /58 */ 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, /* /87 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /59 */ /* /88 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /89 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /60 */ 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, /* /90 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00}}},
/* /61 */ /* /91 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /92 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /62 */ 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, /* /93 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00}}},
/* /63 */ /* /94 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /95 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /64 */ 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, /* /96 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}}},
/* /65 */ /* /97 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /98 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /66 */ 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, /* /99 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00}}},
/* /67 */ /* /100 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /101 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /68 */ 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, /* /102 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00}}},
/* /69 */ /* /103 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /104 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /70 */ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, /* /105 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00}}},
/* /71 */ /* /106 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /107 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /72 */ 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, /* /108 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00}}},
/* /73 */ /* /109 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /110 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /74 */ 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, /* /111 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00}}},
/* /75 */ /* /112 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /113 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /76 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, /* /114 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00}}},
/* /77 */ /* /115 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /116 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /78 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, /* /117 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00}}},
/* /79 */ /* /118 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /119 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /80 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /* /120 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}}},
/* /81 */ /* /121 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /122 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /82 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, /* /123 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0}}},
/* /83 */ /* /124 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /125 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /84 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8}}},
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, /* /126 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}}, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc}}},
/* /85 */ /* /127 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}}},
0x00, 0x00, 0x00, 0x00, 0x00}}}, /* /128 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
/* /86 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}}};
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /87 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /88 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00}}},
/* /89 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x80, 0x00, 0x00, 0x00, 0x00}}},
/* /90 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xc0, 0x00, 0x00, 0x00, 0x00}}},
/* /91 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xe0, 0x00, 0x00, 0x00, 0x00}}},
/* /92 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xf0, 0x00, 0x00, 0x00, 0x00}}},
/* /93 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xf8, 0x00, 0x00, 0x00, 0x00}}},
/* /94 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xfc, 0x00, 0x00, 0x00, 0x00}}},
/* /95 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xfe, 0x00, 0x00, 0x00, 0x00}}},
/* /96 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00}}},
/* /97 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x80, 0x00, 0x00, 0x00}}},
/* /98 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xc0, 0x00, 0x00, 0x00}}},
/* /99 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xe0, 0x00, 0x00, 0x00}}},
/* /100 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xf0, 0x00, 0x00, 0x00}}},
/* /101 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xf8, 0x00, 0x00, 0x00}}},
/* /102 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfc, 0x00, 0x00, 0x00}}},
/* /103 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe, 0x00, 0x00, 0x00}}},
/* /104 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00}}},
/* /105 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x80, 0x00, 0x00}}},
/* /106 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xc0, 0x00, 0x00}}},
/* /107 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xe0, 0x00, 0x00}}},
/* /108 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xf0, 0x00, 0x00}}},
/* /109 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xf8, 0x00, 0x00}}},
/* /110 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfc, 0x00, 0x00}}},
/* /111 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfe, 0x00, 0x00}}},
/* /112 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x00}}},
/* /113 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x80, 0x00}}},
/* /114 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xc0, 0x00}}},
/* /115 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xe0, 0x00}}},
/* /116 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xf0, 0x00}}},
/* /117 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xf8, 0x00}}},
/* /118 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfc, 0x00}}},
/* /119 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfe, 0x00}}},
/* /120 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00}}},
/* /121 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x80}}},
/* /122 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xc0}}},
/* /123 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xe0}}},
/* /124 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf0}}},
/* /125 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf8}}},
/* /126 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfc}}},
/* /127 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe}}},
/* /128 */
{{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff}}}};
/* Number of bits in prefix type. */ /* Number of bits in prefix type. */
#ifndef PNBBY #ifndef PNBBY
@ -429,6 +301,18 @@ static const struct in6_addr maskbytes6[] = {
#define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) #define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff)
static int is_zero_mac(const struct ethaddr *mac)
{
int i = 0;
for (i = 0; i < ETH_ALEN; i++) {
if (mac->octet[i])
return 0;
}
return 1;
}
unsigned int prefix_bit(const u_char *prefix, const u_char prefixlen) unsigned int prefix_bit(const u_char *prefix, const u_char prefixlen)
{ {
unsigned int offset = prefixlen / 8; unsigned int offset = prefixlen / 8;
@ -450,6 +334,8 @@ int str2family(const char *string)
return AF_INET6; return AF_INET6;
else if (!strcmp("ethernet", string)) else if (!strcmp("ethernet", string))
return AF_ETHERNET; return AF_ETHERNET;
else if (!strcmp("evpn", string))
return AF_EVPN;
return -1; return -1;
} }
@ -462,6 +348,7 @@ int afi2family(afi_t afi)
return AF_INET6; return AF_INET6;
else if (afi == AFI_L2VPN) else if (afi == AFI_L2VPN)
return AF_ETHERNET; return AF_ETHERNET;
/* NOTE: EVPN code should NOT use this interface. */
return 0; return 0;
} }
@ -471,7 +358,7 @@ afi_t family2afi(int family)
return AFI_IP; return AFI_IP;
else if (family == AF_INET6) else if (family == AF_INET6)
return AFI_IP6; return AFI_IP6;
else if (family == AF_ETHERNET) else if (family == AF_ETHERNET || family == AF_EVPN)
return AFI_L2VPN; return AFI_L2VPN;
return 0; return 0;
} }
@ -577,6 +464,9 @@ void prefix_copy(struct prefix *dest, const struct prefix *src)
else if (src->family == AF_INET6) else if (src->family == AF_INET6)
dest->u.prefix6 = src->u.prefix6; dest->u.prefix6 = src->u.prefix6;
else if (src->family == AF_ETHERNET) { else if (src->family == AF_ETHERNET) {
memcpy(&dest->u.prefix_eth, &src->u.prefix_eth,
sizeof(struct ethaddr));
} else if (src->family == AF_EVPN) {
memcpy(&dest->u.prefix_evpn, &src->u.prefix_evpn, memcpy(&dest->u.prefix_evpn, &src->u.prefix_evpn,
sizeof(struct evpn_addr)); sizeof(struct evpn_addr));
} else if (src->family == AF_UNSPEC) { } else if (src->family == AF_UNSPEC) {
@ -615,6 +505,10 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2)
&p2->u.prefix6.s6_addr)) &p2->u.prefix6.s6_addr))
return 1; return 1;
if (p1->family == AF_ETHERNET) if (p1->family == AF_ETHERNET)
if (!memcmp(&p1->u.prefix_eth, &p2->u.prefix_eth,
sizeof(struct ethaddr)))
return 1;
if (p1->family == AF_EVPN)
if (!memcmp(&p1->u.prefix_evpn, &p2->u.prefix_evpn, if (!memcmp(&p1->u.prefix_evpn, &p2->u.prefix_evpn,
sizeof(struct evpn_addr))) sizeof(struct evpn_addr)))
return 1; return 1;
@ -679,6 +573,8 @@ int prefix_common_bits(const struct prefix *p1, const struct prefix *p2)
if (p1->family == AF_INET6) if (p1->family == AF_INET6)
length = IPV6_MAX_BYTELEN; length = IPV6_MAX_BYTELEN;
if (p1->family == AF_ETHERNET) if (p1->family == AF_ETHERNET)
length = ETH_ALEN;
if (p1->family == AF_EVPN)
length = 8 * sizeof(struct evpn_addr); length = 8 * sizeof(struct evpn_addr);
if (p1->family != p2->family || !length) if (p1->family != p2->family || !length)
@ -707,6 +603,8 @@ const char *prefix_family_str(const struct prefix *p)
return "inet6"; return "inet6";
if (p->family == AF_ETHERNET) if (p->family == AF_ETHERNET)
return "ether"; return "ether";
if (p->family == AF_EVPN)
return "evpn";
return "unspec"; return "unspec";
} }
@ -783,6 +681,13 @@ int str2prefix_eth(const char *str, struct prefix_eth *p)
const char *str_addr = str; const char *str_addr = str;
unsigned int a[6]; unsigned int a[6];
int i; int i;
bool slash = false;
if (!strcmp(str, "any")) {
memset(p, 0, sizeof(*p));
p->family = AF_ETHERNET;
return 1;
}
/* Find slash inside string. */ /* Find slash inside string. */
pnt = strchr(str, '/'); pnt = strchr(str, '/');
@ -800,6 +705,7 @@ int str2prefix_eth(const char *str, struct prefix_eth *p)
*(cp + (pnt - str)) = '\0'; *(cp + (pnt - str)) = '\0';
str_addr = cp; str_addr = cp;
slash = true;
} }
/* Convert string to prefix. */ /* Convert string to prefix. */
@ -814,6 +720,15 @@ int str2prefix_eth(const char *str, struct prefix_eth *p)
} }
p->prefixlen = plen; p->prefixlen = plen;
p->family = AF_ETHERNET; p->family = AF_ETHERNET;
/*
* special case to allow old configurations to work
* Since all zero's is implicitly meant to allow
* a comparison to zero, let's assume
*/
if (!slash && is_zero_mac(&(p->eth_addr)))
p->prefixlen = 0;
ret = 1; ret = 1;
done: done:
@ -1063,6 +978,7 @@ int prefix_blen(const struct prefix *p)
break; break;
case AF_ETHERNET: case AF_ETHERNET:
return ETH_ALEN; return ETH_ALEN;
break;
} }
return 0; return 0;
} }
@ -1090,7 +1006,7 @@ int str2prefix(const char *str, struct prefix *p)
return 0; return 0;
} }
static const char *prefixeth2str(const struct prefix *p, char *str, int size) static const char *prefixevpn2str(const struct prefix *p, char *str, int size)
{ {
u_char family; u_char family;
char buf[PREFIX2STR_BUFFER]; char buf[PREFIX2STR_BUFFER];
@ -1134,12 +1050,8 @@ static const char *prefixeth2str(const struct prefix *p, char *str, int size)
PREFIX2STR_BUFFER), PREFIX2STR_BUFFER),
p->prefixlen); p->prefixlen);
} else { } else {
sprintf(str, "UNK AF_ETHER prefix"); sprintf(str, "Unsupported EVPN route type %d",
snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d", p->u.prefix_evpn.route_type);
p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1],
p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3],
p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5],
p->prefixlen);
} }
return str; return str;
@ -1159,7 +1071,13 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size)
break; break;
case AF_ETHERNET: case AF_ETHERNET:
prefixeth2str(p, str, size); snprintf(str, size, "%s/%d",
prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf)),
p->prefixlen);
break;
case AF_EVPN:
prefixevpn2str(p, str, size);
break; break;
default: default:

View File

@ -116,7 +116,18 @@ struct evpn_addr {
#endif #endif
#endif #endif
/* IPv4 and IPv6 unified prefix structure. */ /* The 'family' in the prefix structure is internal to FRR and need not
* map to standard OS AF_ definitions except where needed for interacting
* with the kernel. However, AF_ definitions are currently in use and
* prevalent across the code. Define a new FRR-specific AF for EVPN to
* distinguish between 'ethernet' (MAC-only) and 'evpn' prefixes and
* ensure it does not conflict with any OS AF_ definition.
*/
#if !defined(AF_EVPN)
#define AF_EVPN (AF_MAX + 1)
#endif
/* FRR generic prefix structure. */
struct prefix { struct prefix {
u_char family; u_char family;
u_char prefixlen; u_char prefixlen;
@ -131,7 +142,7 @@ struct prefix {
struct ethaddr prefix_eth; /* AF_ETHERNET */ struct ethaddr prefix_eth; /* AF_ETHERNET */
u_char val[8]; u_char val[8];
uintptr_t ptr; uintptr_t ptr;
struct evpn_addr prefix_evpn; struct evpn_addr prefix_evpn; /* AF_EVPN */
} u __attribute__((aligned(8))); } u __attribute__((aligned(8)));
}; };
@ -356,6 +367,7 @@ static inline int ipv6_martian(struct in6_addr *addr)
} }
extern int all_digit(const char *); extern int all_digit(const char *);
extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p);
/* NOTE: This routine expects the address argument in network byte order. */ /* NOTE: This routine expects the address argument in network byte order. */
static inline int ipv4_martian(struct in_addr *addr) static inline int ipv4_martian(struct in_addr *addr)

View File

@ -111,6 +111,7 @@ typedef enum {
ZEBRA_FEC_REGISTER, ZEBRA_FEC_REGISTER,
ZEBRA_FEC_UNREGISTER, ZEBRA_FEC_UNREGISTER,
ZEBRA_FEC_UPDATE, ZEBRA_FEC_UPDATE,
ZEBRA_ADVERTISE_DEFAULT_GW,
ZEBRA_ADVERTISE_ALL_VNI, ZEBRA_ADVERTISE_ALL_VNI,
ZEBRA_VNI_ADD, ZEBRA_VNI_ADD,
ZEBRA_VNI_DEL, ZEBRA_VNI_DEL,
@ -305,6 +306,10 @@ struct zapi_pw_status {
uint32_t status; uint32_t status;
}; };
/* Zebra MAC types */
#define ZEBRA_MAC_TYPE_STICKY 0x01 /* Sticky MAC*/
#define ZEBRA_MAC_TYPE_GW 0x02 /* gateway (SVI) mac*/
/* Prototypes of zebra client service functions. */ /* Prototypes of zebra client service functions. */
extern struct zclient *zclient_new(struct thread_master *); extern struct zclient *zclient_new(struct thread_master *);
extern void zclient_init(struct zclient *, int, u_short); extern void zclient_init(struct zclient *, int, u_short);

View File

@ -432,6 +432,8 @@ end
ctx_keys.append("address-family ipv6 unicast") ctx_keys.append("address-family ipv6 unicast")
elif line == "address-family ipv4": elif line == "address-family ipv4":
ctx_keys.append("address-family ipv4 unicast") ctx_keys.append("address-family ipv4 unicast")
elif line == "address-family evpn":
ctx_keys.append("address-family l2vpn evpn")
else: else:
ctx_keys.append(line) ctx_keys.append(line)
@ -745,6 +747,37 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
lines_to_del_to_del.append((ctx_keys, None)) lines_to_del_to_del.append((ctx_keys, None))
lines_to_add_to_del.append(((tmpline,), None)) lines_to_add_to_del.append(((tmpline,), None))
if (len(ctx_keys) == 3 and
ctx_keys[0].startswith('router bgp') and
ctx_keys[1] == 'address-family l2vpn evpn' and
ctx_keys[2].startswith('vni')):
re_route_target = re.search('^route-target import (.*)$', line) if line is not None else False
if re_route_target:
rt = re_route_target.group(1).strip()
route_target_import_line = line
route_target_export_line = "route-target export %s" % rt
route_target_both_line = "route-target both %s" % rt
found_route_target_export_line = line_exist(lines_to_del, ctx_keys, route_target_export_line)
found_route_target_both_line = line_exist(lines_to_add, ctx_keys, route_target_both_line)
'''
If the running configs has
route-target import 1:1
route-target export 1:1
and the config we are reloading against has
route-target both 1:1
then we can ignore deleting the import/export and ignore adding the 'both'
'''
if found_route_target_export_line and found_route_target_both_line:
lines_to_del_to_del.append((ctx_keys, route_target_import_line))
lines_to_del_to_del.append((ctx_keys, route_target_export_line))
lines_to_add_to_del.append((ctx_keys, route_target_both_line))
if not deleted: if not deleted:
found_add_line = line_exist(lines_to_add, ctx_keys, line) found_add_line = line_exist(lines_to_add, ctx_keys, line)
@ -822,6 +855,13 @@ def compare_context_objects(newconf, running):
elif "router bgp" in running_ctx_keys[0] and len(running_ctx_keys) > 1 and delete_bgpd: elif "router bgp" in running_ctx_keys[0] and len(running_ctx_keys) > 1 and delete_bgpd:
continue continue
# Delete an entire vni sub-context under "address-family l2vpn evpn"
elif ("router bgp" in running_ctx_keys[0] and
len(running_ctx_keys) > 2 and
running_ctx_keys[1].startswith('address-family l2vpn evpn') and
running_ctx_keys[2].startswith('vni ')):
lines_to_del.append((running_ctx_keys, None))
elif ("router bgp" in running_ctx_keys[0] and elif ("router bgp" in running_ctx_keys[0] and
len(running_ctx_keys) > 1 and len(running_ctx_keys) > 1 and
running_ctx_keys[1].startswith('address-family')): running_ctx_keys[1].startswith('address-family')):

View File

@ -1164,10 +1164,10 @@ DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd,
} }
#if defined(HAVE_CUMULUS) #if defined(HAVE_CUMULUS)
DEFUNSH(VTYSH_BGPD, address_family_evpn2, address_family_evpn2_cmd, DEFUNSH_HIDDEN(VTYSH_BGPD, address_family_evpn2, address_family_evpn2_cmd,
"address-family evpn", "address-family evpn",
"Enter Address Family command mode\n" "Enter Address Family command mode\n"
"EVPN Address family\n") "EVPN Address family\n")
{ {
vty->node = BGP_EVPN_NODE; vty->node = BGP_EVPN_NODE;
return CMD_SUCCESS; return CMD_SUCCESS;

View File

@ -224,6 +224,10 @@ void vtysh_config_parse_line(void *arg, const char *line)
strlen("ipv6 access-list")) strlen("ipv6 access-list"))
== 0) == 0)
config = config_get(ACCESS_IPV6_NODE, line); config = config_get(ACCESS_IPV6_NODE, line);
else if (strncmp(line, "mac access-list",
strlen("mac access-list"))
== 0)
config = config_get(ACCESS_MAC_NODE, line);
else if (strncmp(line, "ip prefix-list", else if (strncmp(line, "ip prefix-list",
strlen("ip prefix-list")) strlen("ip prefix-list"))
== 0) == 0)
@ -302,9 +306,10 @@ void vtysh_config_parse_line(void *arg, const char *line)
#define NO_DELIMITER(I) \ #define NO_DELIMITER(I) \
((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \ ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \
|| (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \ || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \
|| (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE \ || (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE \
|| (I) == SERVICE_NODE || (I) == FORWARDING_NODE || (I) == DEBUG_NODE \ || (I) == PREFIX_IPV6_NODE || (I) == SERVICE_NODE \
|| (I) == AAA_NODE || (I) == VRF_DEBUG_NODE || (I) == MPLS_NODE) || (I) == FORWARDING_NODE || (I) == DEBUG_NODE || (I) == AAA_NODE \
|| (I) == VRF_DEBUG_NODE || (I) == MPLS_NODE)
/* Display configuration to file pointer. */ /* Display configuration to file pointer. */
void vtysh_config_dump(FILE *fp) void vtysh_config_dump(FILE *fp)

View File

@ -251,6 +251,8 @@ static void netlink_determine_zebra_iftype(char *kind, zebra_iftype_t *zif_type)
*zif_type = ZEBRA_IF_VLAN; *zif_type = ZEBRA_IF_VLAN;
else if (strcmp(kind, "vxlan") == 0) else if (strcmp(kind, "vxlan") == 0)
*zif_type = ZEBRA_IF_VXLAN; *zif_type = ZEBRA_IF_VXLAN;
else if (strcmp(kind, "macvlan") == 0)
*zif_type = ZEBRA_IF_MACVLAN;
} }
// Temporary Assignments to compile on older platforms. // Temporary Assignments to compile on older platforms.
@ -401,16 +403,19 @@ static int get_iflink_speed(const char *ifname)
/* use ioctl to get IP address of an interface */ /* use ioctl to get IP address of an interface */
sd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); sd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sd < 0) { if (sd < 0) {
zlog_debug("Failure to read interface %s speed: %d %s", ifname, if (IS_ZEBRA_DEBUG_KERNEL)
errno, safe_strerror(errno)); zlog_debug("Failure to read interface %s speed: %d %s",
ifname, errno, safe_strerror(errno));
return 0; return 0;
} }
/* Get the current link state for the interface */ /* Get the current link state for the interface */
rc = ioctl(sd, SIOCETHTOOL, (char *)&ifdata); rc = ioctl(sd, SIOCETHTOOL, (char *)&ifdata);
if (rc < 0) { if (rc < 0) {
zlog_debug("IOCTL failure to read interface %s speed: %d %s", if (IS_ZEBRA_DEBUG_KERNEL)
ifname, errno, safe_strerror(errno)); zlog_debug(
"IOCTL failure to read interface %s speed: %d %s",
ifname, errno, safe_strerror(errno));
ecmd.speed_hi = 0; ecmd.speed_hi = 0;
ecmd.speed = 0; ecmd.speed = 0;
} }

View File

@ -186,11 +186,12 @@ struct rtadvconf {
/* Zebra interface type - ones of interest. */ /* Zebra interface type - ones of interest. */
typedef enum { typedef enum {
ZEBRA_IF_VXLAN, /* VxLAN interface */ ZEBRA_IF_VXLAN, /* VxLAN interface */
ZEBRA_IF_VRF, /* VRF device */ ZEBRA_IF_VRF, /* VRF device */
ZEBRA_IF_BRIDGE, /* bridge device */ ZEBRA_IF_BRIDGE, /* bridge device */
ZEBRA_IF_VLAN, /* VLAN sub-interface */ ZEBRA_IF_VLAN, /* VLAN sub-interface */
ZEBRA_IF_OTHER, /* Anything else */ ZEBRA_IF_MACVLAN, /* MAC VLAN interface*/
ZEBRA_IF_OTHER, /* Anything else */
} zebra_iftype_t; } zebra_iftype_t;
/* Zebra "slave" interface type */ /* Zebra "slave" interface type */
@ -295,6 +296,9 @@ static inline void zebra_if_set_ziftype(struct interface *ifp,
#define IS_ZEBRA_IF_VXLAN(ifp) \ #define IS_ZEBRA_IF_VXLAN(ifp) \
(((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VXLAN) (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VXLAN)
#define IS_ZEBRA_IF_MACVLAN(ifp) \
(((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_MACVLAN)
#define IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) \ #define IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) \
(((struct zebra_if *)(ifp->info))->zif_slave_type \ (((struct zebra_if *)(ifp->info))->zif_slave_type \
== ZEBRA_IF_SLAVE_BRIDGE) == ZEBRA_IF_SLAVE_BRIDGE)

View File

@ -41,6 +41,7 @@
#include "zebra/debug.h" #include "zebra/debug.h"
#include "zebra/router-id.h" #include "zebra/router-id.h"
#include "zebra/zebra_memory.h" #include "zebra/zebra_memory.h"
#include "zebra/zebra_vxlan.h"
#define ZEBRA_PTM_SUPPORT #define ZEBRA_PTM_SUPPORT
@ -402,6 +403,8 @@ void zebra_interface_address_add_update(struct interface *ifp,
zlog_warn( zlog_warn(
"WARNING: advertising address to clients that is not yet usable."); "WARNING: advertising address to clients that is not yet usable.");
zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 1);
router_id_add_address(ifc); router_id_add_address(ifc);
for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))
@ -428,6 +431,8 @@ void zebra_interface_address_delete_update(struct interface *ifp,
prefix2str(p, buf, sizeof(buf)), ifc->ifp->name); prefix2str(p, buf, sizeof(buf)), ifc->ifp->name);
} }
zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 0);
router_id_del_address(ifc); router_id_del_address(ifc);
for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client))

View File

@ -1321,9 +1321,9 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty)
default: default:
break; break;
} }
vty_out(vty, "%s", vty_out(vty, "%s", CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)
CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)" ? " (installed)"
: ""); : "");
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
@ -2807,6 +2807,8 @@ void zebra_mpls_close_tables(struct zebra_vrf *zvrf)
hash_free(zvrf->lsp_table); hash_free(zvrf->lsp_table);
hash_clean(zvrf->slsp_table, NULL); hash_clean(zvrf->slsp_table, NULL);
hash_free(zvrf->slsp_table); hash_free(zvrf->slsp_table);
route_table_finish(zvrf->fec_table[AFI_IP]);
route_table_finish(zvrf->fec_table[AFI_IP6]);
} }
/* /*

View File

@ -107,6 +107,11 @@ struct zebra_vrf {
*/ */
int advertise_all_vni; int advertise_all_vni;
/*
* Whether we are advertising g/w macip in EVPN or not.
*/
int advertise_gw_macip;
/* Route Installs */ /* Route Installs */
uint64_t installs; uint64_t installs;
uint64_t removals; uint64_t removals;

View File

@ -2285,89 +2285,100 @@ DEFUN (show_vrf,
DEFUN (show_evpn_vni, DEFUN (show_evpn_vni,
show_evpn_vni_cmd, show_evpn_vni_cmd,
"show evpn vni", "show evpn vni [json]",
SHOW_STR SHOW_STR
"EVPN\n" "EVPN\n"
"VxLAN information\n") "VxLAN information\n"
JSON_STR)
{ {
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
u_char uj = use_json(argc, argv);
zvrf = vrf_info_lookup(VRF_DEFAULT); zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_vnis(vty, zvrf); zebra_vxlan_print_vnis(vty, zvrf, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_evpn_vni_vni, DEFUN (show_evpn_vni_vni,
show_evpn_vni_vni_cmd, show_evpn_vni_vni_cmd,
"show evpn vni " CMD_VNI_RANGE, "show evpn vni " CMD_VNI_RANGE "[json]",
SHOW_STR SHOW_STR
"EVPN\n" "EVPN\n"
"VxLAN Network Identifier\n" "VxLAN Network Identifier\n"
"VNI number\n") "VNI number\n"
JSON_STR)
{ {
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
vni_t vni; vni_t vni;
u_char uj = use_json(argc, argv);
vni = strtoul(argv[3]->arg, NULL, 10); vni = strtoul(argv[3]->arg, NULL, 10);
zvrf = vrf_info_lookup(VRF_DEFAULT); zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_vni(vty, zvrf, vni); zebra_vxlan_print_vni(vty, zvrf, vni, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_evpn_mac_vni, DEFUN (show_evpn_mac_vni,
show_evpn_mac_vni_cmd, show_evpn_mac_vni_cmd,
"show evpn mac vni " CMD_VNI_RANGE, "show evpn mac vni " CMD_VNI_RANGE "[json]",
SHOW_STR SHOW_STR
"EVPN\n" "EVPN\n"
"MAC addresses\n" "MAC addresses\n"
"VxLAN Network Identifier\n" "VxLAN Network Identifier\n"
"VNI number\n") "VNI number\n"
JSON_STR)
{ {
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
vni_t vni; vni_t vni;
u_char uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10); vni = strtoul(argv[4]->arg, NULL, 10);
zvrf = vrf_info_lookup(VRF_DEFAULT); zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_macs_vni(vty, zvrf, vni); zebra_vxlan_print_macs_vni(vty, zvrf, vni, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_evpn_mac_vni_all, DEFUN (show_evpn_mac_vni_all,
show_evpn_mac_vni_all_cmd, show_evpn_mac_vni_all_cmd,
"show evpn mac vni all", "show evpn mac vni all [json]",
SHOW_STR SHOW_STR
"EVPN\n" "EVPN\n"
"MAC addresses\n" "MAC addresses\n"
"VxLAN Network Identifier\n" "VxLAN Network Identifier\n"
"All VNIs\n") "All VNIs\n"
JSON_STR)
{ {
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
u_char uj = use_json(argc, argv);
zvrf = vrf_info_lookup(VRF_DEFAULT); zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_macs_all_vni(vty, zvrf); zebra_vxlan_print_macs_all_vni(vty, zvrf, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_evpn_mac_vni_all_vtep, DEFUN (show_evpn_mac_vni_all_vtep,
show_evpn_mac_vni_all_vtep_cmd, show_evpn_mac_vni_all_vtep_cmd,
"show evpn mac vni all vtep A.B.C.D", "show evpn mac vni all vtep A.B.C.D [json]",
SHOW_STR SHOW_STR
"EVPN\n" "EVPN\n"
"MAC addresses\n" "MAC addresses\n"
"VxLAN Network Identifier\n" "VxLAN Network Identifier\n"
"All VNIs\n" "All VNIs\n"
"Remote VTEP\n" "Remote VTEP\n"
"Remote VTEP IP address\n") "Remote VTEP IP address\n"
JSON_STR)
{ {
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
struct in_addr vtep_ip; struct in_addr vtep_ip;
u_char uj = use_json(argc, argv);
if (!inet_aton(argv[6]->arg, &vtep_ip)) { if (!inet_aton(argv[6]->arg, &vtep_ip)) {
vty_out(vty, "%% Malformed VTEP IP address\n"); if (!uj)
vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING; return CMD_WARNING;
} }
zvrf = vrf_info_lookup(VRF_DEFAULT); zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_macs_all_vni_vtep(vty, zvrf, vtep_ip); zebra_vxlan_print_macs_all_vni_vtep(vty, zvrf, vtep_ip, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
@ -2400,112 +2411,125 @@ DEFUN (show_evpn_mac_vni_mac,
DEFUN (show_evpn_mac_vni_vtep, DEFUN (show_evpn_mac_vni_vtep,
show_evpn_mac_vni_vtep_cmd, show_evpn_mac_vni_vtep_cmd,
"show evpn mac vni " CMD_VNI_RANGE " vtep A.B.C.D", "show evpn mac vni " CMD_VNI_RANGE " vtep A.B.C.D" "[json]",
SHOW_STR SHOW_STR
"EVPN\n" "EVPN\n"
"MAC addresses\n" "MAC addresses\n"
"VxLAN Network Identifier\n" "VxLAN Network Identifier\n"
"VNI number\n" "VNI number\n"
"Remote VTEP\n" "Remote VTEP\n"
"Remote VTEP IP address\n") "Remote VTEP IP address\n"
JSON_STR)
{ {
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
vni_t vni; vni_t vni;
struct in_addr vtep_ip; struct in_addr vtep_ip;
u_char uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10); vni = strtoul(argv[4]->arg, NULL, 10);
if (!inet_aton(argv[6]->arg, &vtep_ip)) { if (!inet_aton(argv[6]->arg, &vtep_ip)) {
vty_out(vty, "%% Malformed VTEP IP address\n"); if (!uj)
vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING; return CMD_WARNING;
} }
zvrf = vrf_info_lookup(VRF_DEFAULT); zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_macs_vni_vtep(vty, zvrf, vni, vtep_ip); zebra_vxlan_print_macs_vni_vtep(vty, zvrf, vni, vtep_ip, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_evpn_neigh_vni, DEFUN (show_evpn_neigh_vni,
show_evpn_neigh_vni_cmd, show_evpn_neigh_vni_cmd,
"show evpn arp-cache vni " CMD_VNI_RANGE, "show evpn arp-cache vni " CMD_VNI_RANGE "[json]",
SHOW_STR SHOW_STR
"EVPN\n" "EVPN\n"
"ARP and ND cache\n" "ARP and ND cache\n"
"VxLAN Network Identifier\n" "VxLAN Network Identifier\n"
"VNI number\n") "VNI number\n"
JSON_STR)
{ {
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
vni_t vni; vni_t vni;
u_char uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10); vni = strtoul(argv[4]->arg, NULL, 10);
zvrf = vrf_info_lookup(VRF_DEFAULT); zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_neigh_vni(vty, zvrf, vni); zebra_vxlan_print_neigh_vni(vty, zvrf, vni, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_evpn_neigh_vni_all, DEFUN (show_evpn_neigh_vni_all,
show_evpn_neigh_vni_all_cmd, show_evpn_neigh_vni_all_cmd,
"show evpn arp-cache vni all", "show evpn arp-cache vni all [json]",
SHOW_STR SHOW_STR
"EVPN\n" "EVPN\n"
"ARP and ND cache\n" "ARP and ND cache\n"
"VxLAN Network Identifier\n" "VxLAN Network Identifier\n"
"All VNIs\n") "All VNIs\n"
JSON_STR)
{ {
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
u_char uj = use_json(argc, argv);
zvrf = vrf_info_lookup(VRF_DEFAULT); zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_neigh_all_vni(vty, zvrf); zebra_vxlan_print_neigh_all_vni(vty, zvrf, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_evpn_neigh_vni_neigh, DEFUN (show_evpn_neigh_vni_neigh,
show_evpn_neigh_vni_neigh_cmd, show_evpn_neigh_vni_neigh_cmd,
"show evpn arp-cache vni " CMD_VNI_RANGE " ip WORD", "show evpn arp-cache vni " CMD_VNI_RANGE " ip WORD [json]",
SHOW_STR SHOW_STR
"EVPN\n" "EVPN\n"
"ARP and ND cache\n" "ARP and ND cache\n"
"VxLAN Network Identifier\n" "VxLAN Network Identifier\n"
"VNI number\n" "VNI number\n"
"Neighbor\n" "Neighbor\n"
"Neighbor address (IPv4 or IPv6 address)\n") "Neighbor address (IPv4 or IPv6 address)\n"
JSON_STR)
{ {
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
vni_t vni; vni_t vni;
struct ipaddr ip; struct ipaddr ip;
u_char uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10); vni = strtoul(argv[4]->arg, NULL, 10);
if (str2ipaddr(argv[6]->arg, &ip) != 0) { if (str2ipaddr(argv[6]->arg, &ip) != 0) {
vty_out(vty, "%% Malformed Neighbor address\n"); if (!uj)
vty_out(vty, "%% Malformed Neighbor address\n");
return CMD_WARNING; return CMD_WARNING;
} }
zvrf = vrf_info_lookup(VRF_DEFAULT); zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_specific_neigh_vni(vty, zvrf, vni, &ip); zebra_vxlan_print_specific_neigh_vni(vty, zvrf, vni, &ip, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFUN (show_evpn_neigh_vni_vtep, DEFUN (show_evpn_neigh_vni_vtep,
show_evpn_neigh_vni_vtep_cmd, show_evpn_neigh_vni_vtep_cmd,
"show evpn arp-cache vni " CMD_VNI_RANGE " vtep A.B.C.D", "show evpn arp-cache vni " CMD_VNI_RANGE " vtep A.B.C.D [json]",
SHOW_STR SHOW_STR
"EVPN\n" "EVPN\n"
"ARP and ND cache\n" "ARP and ND cache\n"
"VxLAN Network Identifier\n" "VxLAN Network Identifier\n"
"VNI number\n" "VNI number\n"
"Remote VTEP\n" "Remote VTEP\n"
"Remote VTEP IP address\n") "Remote VTEP IP address\n"
JSON_STR)
{ {
struct zebra_vrf *zvrf; struct zebra_vrf *zvrf;
vni_t vni; vni_t vni;
struct in_addr vtep_ip; struct in_addr vtep_ip;
u_char uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10); vni = strtoul(argv[4]->arg, NULL, 10);
if (!inet_aton(argv[6]->arg, &vtep_ip)) { if (!inet_aton(argv[6]->arg, &vtep_ip)) {
vty_out(vty, "%% Malformed VTEP IP address\n"); if (!uj)
vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING; return CMD_WARNING;
} }
zvrf = vrf_info_lookup(VRF_DEFAULT); zvrf = vrf_info_lookup(VRF_DEFAULT);
zebra_vxlan_print_neigh_vni_vtep(vty, zvrf, vni, vtep_ip); zebra_vxlan_print_neigh_vni_vtep(vty, zvrf, vni, vtep_ip, uj);
return CMD_SUCCESS; return CMD_SUCCESS;
} }

File diff suppressed because it is too large Load Diff

View File

@ -41,33 +41,44 @@
#define ZEBRA_VXLIF_MASTER_CHANGE 0x2 #define ZEBRA_VXLIF_MASTER_CHANGE 0x2
#define ZEBRA_VXLIF_VLAN_CHANGE 0x4 #define ZEBRA_VXLIF_VLAN_CHANGE 0x4
#define VNI_STR_LEN 32
extern void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, extern void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni); vni_t vni, u_char use_json);
extern void zebra_vxlan_print_macs_all_vni(struct vty *vty, extern void zebra_vxlan_print_macs_all_vni(struct vty *vty,
struct zebra_vrf *zvrf); struct zebra_vrf *zvrf,
u_char use_json);
extern void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty, extern void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty,
struct zebra_vrf *zvrf, struct zebra_vrf *zvrf,
struct in_addr vtep_ip); struct in_addr vtep_ip,
u_char use_json);
extern void zebra_vxlan_print_specific_mac_vni(struct vty *vty, extern void zebra_vxlan_print_specific_mac_vni(struct vty *vty,
struct zebra_vrf *zvrf, struct zebra_vrf *zvrf,
vni_t vni, struct ethaddr *mac); vni_t vni, struct ethaddr *mac);
extern void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, extern void zebra_vxlan_print_macs_vni_vtep(struct vty *vty,
struct zebra_vrf *zvrf, vni_t vni, struct zebra_vrf *zvrf, vni_t vni,
struct in_addr vtep_ip); struct in_addr vtep_ip,
u_char use_json);
extern void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, extern void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni); vni_t vni, u_char use_json);
extern void zebra_vxlan_print_neigh_all_vni(struct vty *vty, extern void zebra_vxlan_print_neigh_all_vni(struct vty *vty,
struct zebra_vrf *zvrf); struct zebra_vrf *zvrf,
u_char use_json);
extern void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, extern void zebra_vxlan_print_specific_neigh_vni(struct vty *vty,
struct zebra_vrf *zvrf, struct zebra_vrf *zvrf,
vni_t vni, struct ipaddr *ip); vni_t vni, struct ipaddr *ip,
u_char use_json);
extern void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, extern void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty,
struct zebra_vrf *zvrf, vni_t vni, struct zebra_vrf *zvrf, vni_t vni,
struct in_addr vtep_ip); struct in_addr vtep_ip,
u_char use_json);
extern void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, extern void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf,
vni_t vni); vni_t vni, u_char use_json);
extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf); extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf,
u_char use_json);
extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
int add);
extern int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if); extern int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if);
extern int zebra_vxlan_svi_down(struct interface *ifp, extern int zebra_vxlan_svi_down(struct interface *ifp,
struct interface *link_if); struct interface *link_if);
@ -104,6 +115,9 @@ extern int zebra_vxlan_remote_vtep_add(struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf); u_short length, struct zebra_vrf *zvrf);
extern int zebra_vxlan_remote_vtep_del(struct zserv *client, int sock, extern int zebra_vxlan_remote_vtep_del(struct zserv *client, int sock,
u_short length, struct zebra_vrf *zvrf); u_short length, struct zebra_vrf *zvrf);
extern int zebra_vxlan_advertise_gw_macip(struct zserv *client, int sock,
u_short length,
struct zebra_vrf *zvrf);
extern int zebra_vxlan_advertise_all_vni(struct zserv *client, int sock, extern int zebra_vxlan_advertise_all_vni(struct zserv *client, int sock,
u_short length, u_short length,
struct zebra_vrf *zvrf); struct zebra_vrf *zvrf);

View File

@ -63,6 +63,9 @@ struct zebra_vni_t_ {
/* VNI - key */ /* VNI - key */
vni_t vni; vni_t vni;
/* Flag for advertising gw macip */
u_int8_t advertise_gw_macip;
/* Corresponding VxLAN interface. */ /* Corresponding VxLAN interface. */
struct interface *vxlan_if; struct interface *vxlan_if;
@ -112,6 +115,9 @@ struct zebra_mac_t_ {
} fwd_info; } fwd_info;
u_int32_t neigh_refcnt; u_int32_t neigh_refcnt;
/* List of neigh associated with this mac */
struct list *neigh_list;
}; };
/* /*
@ -132,10 +138,21 @@ struct mac_walk_ctx {
struct in_addr r_vtep_ip; /* To walk MACs from specific VTEP */ struct in_addr r_vtep_ip; /* To walk MACs from specific VTEP */
struct vty *vty; /* Used by VTY handlers */ struct vty *vty; /* Used by VTY handlers */
u_int32_t count; /* Used by VTY handlers */ u_int32_t count; /* Used by VTY handlers */
struct json_object *json; /* Used for JSON Output */
}; };
enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 };
#define IS_ZEBRA_NEIGH_ACTIVE(n) n->state == ZEBRA_NEIGH_ACTIVE
#define IS_ZEBRA_NEIGH_INACTIVE(n) n->state == ZEBRA_NEIGH_INACTIVE
#define ZEBRA_NEIGH_SET_ACTIVE(n) n->state = ZEBRA_NEIGH_ACTIVE
#define ZEBRA_NEIGH_SET_INACTIVE(n) n->state = ZEBRA_NEIGH_INACTIVE
/* /*
* Neighbor hash table. * Neighbor hash table.
* *
@ -158,8 +175,10 @@ struct zebra_neigh_t_ {
ifindex_t ifindex; ifindex_t ifindex;
u_int32_t flags; u_int32_t flags;
#define ZEBRA_NEIGH_LOCAL 0x01 #define ZEBRA_NEIGH_LOCAL 0x01
#define ZEBRA_NEIGH_REMOTE 0x02 #define ZEBRA_NEIGH_REMOTE 0x02
enum zebra_neigh_state state;
/* Remote VTEP IP - applicable only for remote neighbors. */ /* Remote VTEP IP - applicable only for remote neighbors. */
struct in_addr r_vtep_ip; struct in_addr r_vtep_ip;
@ -183,9 +202,10 @@ struct neigh_walk_ctx {
struct in_addr r_vtep_ip; /* To walk neighbors from specific VTEP */ struct in_addr r_vtep_ip; /* To walk neighbors from specific VTEP */
struct vty *vty; /* Used by VTY handlers */ struct vty *vty; /* Used by VTY handlers */
u_int32_t count; /* Used by VTY handlers */ u_int32_t count; /* Used by VTY handlers */
u_char addr_width; /* Used by VTY handlers */ u_char addr_width; /* Used by VTY handlers */
struct json_object *json; /* Used for JSON Output */
}; };
#endif /* _ZEBRA_VXLAN_PRIVATE_H */ #endif /* _ZEBRA_VXLAN_PRIVATE_H */

View File

@ -2533,6 +2533,9 @@ static int zebra_client_read(struct thread *thread)
case ZEBRA_FEC_UNREGISTER: case ZEBRA_FEC_UNREGISTER:
zserv_fec_unregister(client, sock, length); zserv_fec_unregister(client, sock, length);
break; break;
case ZEBRA_ADVERTISE_DEFAULT_GW:
zebra_vxlan_advertise_gw_macip(client, sock, length, zvrf);
break;
case ZEBRA_ADVERTISE_ALL_VNI: case ZEBRA_ADVERTISE_ALL_VNI:
zebra_vxlan_advertise_all_vni(client, sock, length, zvrf); zebra_vxlan_advertise_all_vni(client, sock, length, zvrf);
break; break;