void vr_mpls_exit(struct vrouter *router, bool soft_reset) { unsigned int i; struct vr_nexthop *nh; if (!router->vr_max_labels || !router->vr_ilm) return; for (i = 0; i < router->vr_max_labels; i++) { nh = __vrouter_get_label(router, i); if (nh) { vrouter_put_nexthop(nh); __vrouter_set_label(router, i, NULL); } } if (soft_reset == false) { vr_btable_free(router->vr_ilm); router->vr_ilm = NULL; router->vr_max_labels = 0; } return; }
static struct vr_nexthop * vrouter_get_label(unsigned int rid, unsigned int label) { struct vrouter *router = vrouter_get(rid); return __vrouter_get_label(router, label); }
static void vr_flush_entry(struct vrouter *router, struct vr_flow_entry *fe, struct vr_flow_md *flmd, struct vr_forwarding_md *fmd) { struct vr_list_node *head; struct vr_packet_node *pnode; struct vr_packet *pkt; struct vr_interface *vif; head = fe->fe_hold_list.node_p; fe->fe_hold_list.node_p = NULL; while (head) { pnode = (struct vr_packet_node *)head; if (fmd) { fmd->fmd_outer_src_ip = pnode->pl_outer_src_ip; fmd->fmd_label = pnode->pl_label; } pkt = pnode->pl_packet; /* * this is only a security check and not a catch all check. one note * of caution. please do not access pkt->vp_if till the if block is * succesfully bypassed */ vif = __vrouter_get_interface(router, pnode->pl_vif_idx); if (!vif || (pkt->vp_if != vif)) { vr_pfree(pkt, VP_DROP_INVALID_IF); goto loop_continue; } if (!pkt->vp_nh) { if (vif_is_fabric(pkt->vp_if) && fmd && (fmd->fmd_label >= 0)) { pkt->vp_nh = __vrouter_get_label(router, fmd->fmd_label); } } vr_flow_action(router, fe, flmd->flmd_index, pkt, pnode->pl_proto, fmd); loop_continue: head = pnode->pl_node.node_n; vr_free(pnode); } return; }
int __vr_mpls_del(struct vrouter *router, unsigned int label) { struct vr_nexthop *nh; /* hardware packet filtering (Flow Director) support */ nh = __vrouter_get_label(router, label); if (nh) { if (vrouter_host->hos_del_mpls && nh->nh_type == NH_ENCAP && !(nh->nh_flags & NH_FLAG_MCAST)) vrouter_host->hos_del_mpls(router, label); vrouter_put_nexthop(nh); } return __vrouter_set_label(router, label, NULL); }
int vr_mpls_tunnel_type(unsigned int label, unsigned int control_data, unsigned short *reason) { struct vr_nexthop *nh; struct vrouter *router = vrouter_get(0); unsigned short res; if (!router) { res = VP_DROP_MISC; goto fail; } label >>= VR_MPLS_LABEL_SHIFT; if (label >= router->vr_max_labels) { res = VP_DROP_INVALID_LABEL; goto fail; } nh = __vrouter_get_label(router, label); if(!nh) { res = VP_DROP_INVALID_NH; goto fail; } switch(nh->nh_family) { case AF_INET: return PKT_MPLS_TUNNEL_L3; case AF_BRIDGE: if (nh->nh_type != NH_COMPOSITE) { return PKT_MPLS_TUNNEL_L2_UCAST; } if (label < VR_MAX_UCAST_LABELS) { return PKT_MPLS_TUNNEL_L2_MCAST_EVPN; } return PKT_MPLS_TUNNEL_L2_MCAST; default: res = VP_DROP_INVALID_NH; } fail: if (reason) *reason = res; return -1; }
int vr_mpls_dump(vr_mpls_req *r) { int ret = 0; unsigned int i; struct vr_nexthop *nh; struct vrouter *router = vrouter_get(r->mr_rid); struct vr_message_dumper *dumper = NULL; vr_mpls_req req; if (!router && (ret = -ENODEV)) goto generate_response; if ((unsigned int)(r->mr_marker) + 1 >= router->vr_max_labels) goto generate_response; dumper = vr_message_dump_init(r); if (!dumper && (ret = -ENOMEM)) goto generate_response; for (i = (unsigned int)(r->mr_marker + 1); i < router->vr_max_labels; i++) { nh = __vrouter_get_label(router, i); if (nh) { vr_mpls_make_req(&req, nh, i); ret = vr_message_dump_object(dumper, VR_MPLS_OBJECT_ID, &req); if (ret <= 0) break; } } generate_response: vr_message_dump_exit(dumper, ret); return 0; }
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; }