static struct vr_bridge_entry * bridge_lookup(uint8_t *mac, struct vr_forwarding_md *fmd) { struct vr_route_req rt; struct vr_bridge_entry *be; rt.rtr_req.rtr_label_flags = 0; rt.rtr_req.rtr_index = VR_BE_INVALID_INDEX; rt.rtr_req.rtr_mac_size = VR_ETHER_ALEN; rt.rtr_req.rtr_mac = mac; /* If multicast L2 packet, use broadcast composite nexthop */ if (IS_MAC_BMCAST(rt.rtr_req.rtr_mac)) rt.rtr_req.rtr_mac = (int8_t *)vr_bcast_mac; rt.rtr_req.rtr_vrf_id = fmd->fmd_dvrf; be = __bridge_lookup(rt.rtr_req.rtr_vrf_id, &rt); if (be) bridge_update_route_req(be, &rt); if (fmd && (rt.rtr_req.rtr_label_flags & VR_BE_LABEL_VALID_FLAG)) { vr_forwarding_md_set_label(fmd, rt.rtr_req.rtr_label, VR_LABEL_TYPE_UNKNOWN); } return be; }
int vr_mpls_input(struct vrouter *router, struct vr_packet *pkt, struct vr_forwarding_md *fmd) { int ttl, l2_offset = 0; unsigned int label; unsigned short drop_reason; struct vr_nexthop *nh; struct vr_ip *ip; struct vr_forwarding_md c_fmd; if (!fmd) { vr_init_forwarding_md(&c_fmd); fmd = &c_fmd; } label = ntohl(*(unsigned int *)pkt_data(pkt)); ttl = label & 0xFF; label >>= VR_MPLS_LABEL_SHIFT; if (label >= router->vr_max_labels) { drop_reason = VP_DROP_INVALID_LABEL; goto dropit; } if (--ttl <= 0) { drop_reason = VP_DROP_TTL_EXCEEDED; goto dropit; } ip = (struct vr_ip *)pkt_network_header(pkt); fmd->fmd_outer_src_ip = ip->ip_saddr; vr_forwarding_md_set_label(fmd, label, VR_LABEL_TYPE_MPLS); /* Store the TTL in packet. Will be used for multicast replication */ pkt->vp_ttl = ttl; /* drop the TOStack label */ if (!pkt_pull(pkt, VR_MPLS_HDR_LEN)) { drop_reason = VP_DROP_PULL; goto dropit; } nh = __vrouter_get_label(router, label); if (!nh) { drop_reason = VP_DROP_INVALID_LABEL; goto dropit; } /* * Mark it for GRO. Diag, L2 and multicast nexthops unmark if * required */ if (vr_perfr) pkt->vp_flags |= VP_FLAG_GRO; /* Reset the flags which get defined below */ pkt->vp_flags &= ~VP_FLAG_MULTICAST; fmd->fmd_vlan = VLAN_ID_INVALID; if (nh->nh_family == AF_INET) { ip = (struct vr_ip *)pkt_data(pkt); if (vr_ip_is_ip4(ip)) { pkt->vp_type = VP_TYPE_IP; } else if (vr_ip_is_ip6(ip)) { pkt->vp_type = VP_TYPE_IP6; } else { drop_reason = VP_DROP_INVALID_PROTOCOL; goto dropit; } pkt_set_network_header(pkt, pkt->vp_data); pkt_set_inner_network_header(pkt, pkt->vp_data); } else if (nh->nh_family == AF_BRIDGE) { if (nh->nh_type == NH_COMPOSITE) { if (label >= VR_MAX_UCAST_LABELS) l2_offset = VR_L2_MCAST_CTRL_DATA_LEN + VR_VXLAN_HDR_LEN; } if (vr_pkt_type(pkt, l2_offset, fmd) < 0) { drop_reason = VP_DROP_INVALID_PACKET; goto dropit; } } else { drop_reason = VP_DROP_INVALID_NH; goto dropit; } /* * We are typically looking at interface nexthops, and hence we will * hit the vrf of the destination device. But, labels can also point * to composite nexthops (ECMP being case in point), in which case we * will take the vrf from the nexthop. When everything else fails, we * will forward the packet in the vrf in which it came i.e fabric */ if (nh->nh_vrf >= 0) fmd->fmd_dvrf = nh->nh_vrf; else if (nh->nh_dev) fmd->fmd_dvrf = nh->nh_dev->vif_vrf; else fmd->fmd_dvrf = pkt->vp_if->vif_vrf; nh_output(pkt, nh, fmd); return 0; dropit: vr_pfree(pkt, drop_reason); return 0; }