static unsigned char * agent_set_rewrite(struct vr_interface *vif, struct vr_packet *pkt, unsigned char *rewrite, unsigned short len) { unsigned char *head; unsigned int hdr_len; struct agent_hdr *hdr; vr_preset(pkt); hdr_len = sizeof(struct agent_hdr) + len; if (pkt_head_space(pkt) < hdr_len) { pkt = vr_pexpand_head(pkt, hdr_len - pkt_head_space(pkt)); if (!pkt) return NULL; } head = pkt_push(pkt, hdr_len); if (!head) return NULL; /* copy the rewrite first */ memcpy(head, rewrite, len); hdr = (struct agent_hdr *)(head + len); hdr->hdr_ifindex = htons(pkt->vp_if->vif_idx); hdr->hdr_vrf = htons(pkt->vp_if->vif_vrf); /* this needs some thought */ hdr->hdr_cmd = htons(AGENT_TRAP_NEXTHOP); hdr->hdr_cmd_param = 0; return head; }
unsigned int vr_fabric_input(struct vr_interface *vif, struct vr_packet *pkt, unsigned short vlan_id) { int handled = 0; unsigned short pull_len; struct vr_forwarding_md fmd; vr_init_forwarding_md(&fmd); fmd.fmd_vlan = vlan_id; fmd.fmd_dvrf = vif->vif_vrf; if (vr_pkt_type(pkt, 0, &fmd) < 0) { vif_drop_pkt(vif, pkt, 1); return 0; } if (pkt->vp_type == VP_TYPE_IP6) return vif_xconnect(vif, pkt, &fmd); pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt); pkt_pull(pkt, pull_len); if (pkt->vp_type == VP_TYPE_IP || pkt->vp_type == VP_TYPE_IP6) handled = vr_l3_input(pkt, &fmd); else if (pkt->vp_type == VP_TYPE_ARP) handled = vr_arp_input(pkt, &fmd); if (!handled) { pkt_push(pkt, pull_len); return vif_xconnect(vif, pkt, &fmd); } return 0; }
/* * in the rewrite case, we will assume the positive case of caller * passing us valid rewrite ptr and len and will not check for those */ static unsigned char * vif_cmn_rewrite(struct vr_interface *vif, struct vr_packet *pkt, unsigned char *rewrite, unsigned short len) { unsigned char *head; if (pkt_head_space(pkt) < len) { pkt = vr_pexpand_head(pkt, len - pkt_head_space(pkt)); if (!pkt) return NULL; } head = pkt_push(pkt, len); if (!head) return NULL; memcpy(head, rewrite, len); return head; }
bool vr_l2_mcast_control_data_add(struct vr_packet *pkt) { unsigned int *data; if (pkt_head_space(pkt) < VR_L2_MCAST_CTRL_DATA_LEN) { pkt = vr_pexpand_head(pkt, VR_L2_MCAST_CTRL_DATA_LEN - pkt_head_space(pkt)); if (!pkt) return false; } data = (unsigned int *)pkt_push(pkt, VR_L2_MCAST_CTRL_DATA_LEN); if (!data) return false; *data = VR_L2_MCAST_CTRL_DATA; pkt->vp_type = VP_TYPE_L2; pkt->vp_flags |= VP_FLAG_MULTICAST; return true; }
static int agent_send(struct vr_interface *vif, struct vr_packet *pkt, void *ifspecific) { int len; struct agent_hdr *hdr; unsigned char *rewrite; struct vr_interface_stats *stats = vif_get_stats(vif, pkt->vp_cpu); struct vr_packet *pkt_c; struct agent_send_params *params = (struct agent_send_params *)ifspecific; vr_preset(pkt); if (pkt_head_space(pkt) < AGENT_PKT_HEAD_SPACE) { len = pkt_len(pkt); if (agent_trap_may_truncate(params->trap_reason)) { len = MINIMUM(len, VR_AGENT_MIN_PACKET_LEN); } pkt_c = pkt_copy(pkt, 0, len); if (pkt_c) { vr_pfree(pkt, VP_DROP_DUPLICATED); pkt = pkt_c; } } hdr = (struct agent_hdr *)pkt_push(pkt, sizeof(struct agent_hdr)); if (!hdr) goto drop; hdr->hdr_ifindex = htons(pkt->vp_if->vif_idx); hdr->hdr_vrf = htons(params->trap_vrf); hdr->hdr_cmd = htons(params->trap_reason); switch (params->trap_reason) { case AGENT_TRAP_FLOW_MISS: case AGENT_TRAP_ECMP_RESOLVE: case AGENT_TRAP_SOURCE_MISMATCH: if (params->trap_param) hdr->hdr_cmd_param = htonl(*(unsigned int *)(params->trap_param)); break; case AGENT_TRAP_DIAG: if (params->trap_param) hdr->hdr_cmd_param = htonl(*(unsigned int *)(params->trap_param)); break; default: hdr->hdr_cmd_param = 0; break; } rewrite = pkt_push(pkt, VR_ETHER_HLEN); if (!rewrite) goto drop; memcpy(rewrite, vif->vif_rewrite, VR_ETHER_HLEN); return vif->vif_tx(vif, pkt); drop: stats->vis_oerrors++; vr_pfree(pkt, VP_DROP_PUSH); return 0; }
unsigned int vr_bridge_input(struct vrouter *router, struct vr_packet *pkt, struct vr_forwarding_md *fmd) { struct vr_route_req rt; struct vr_forwarding_md cmd; struct vr_nexthop *nh; unsigned short pull_len, overlay_len = VROUTER_L2_OVERLAY_LEN; int reason; 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 =(int8_t *) pkt_data(pkt); /* 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; nh = vr_bridge_lookup(fmd->fmd_dvrf, &rt); if (!nh) { vr_pfree(pkt, VP_DROP_L2_NO_ROUTE); return 0; } if (nh->nh_type == NH_L2_RCV) overlay_len = VROUTER_OVERLAY_LEN; if (pkt->vp_type == VP_TYPE_IP || pkt->vp_type == VP_TYPE_IP6) { if (vif_is_virtual(pkt->vp_if) && vr_from_vm_mss_adj && vr_pkt_from_vm_tcp_mss_adj) { pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt); if (!pkt_pull(pkt, pull_len)) { vr_pfree(pkt, VP_DROP_PULL); return 0; } if ((reason = vr_pkt_from_vm_tcp_mss_adj(pkt, overlay_len))) { vr_pfree(pkt, reason); return 0; } if (!pkt_push(pkt, pull_len)) { vr_pfree(pkt, VP_DROP_PUSH); return 0; } } } /* * If there is a label attached to this bridge entry add the * label */ if (rt.rtr_req.rtr_label_flags & VR_RT_LABEL_VALID_FLAG) { if (!fmd) { vr_init_forwarding_md(&cmd); fmd = &cmd; } fmd->fmd_label = rt.rtr_req.rtr_label; } nh_output(pkt, nh, fmd); return 0; }
unsigned int vr_bridge_input(struct vrouter *router, struct vr_packet *pkt, struct vr_forwarding_md *fmd) { int reason, handled; l4_pkt_type_t l4_type = L4_TYPE_UNKNOWN; unsigned short pull_len, overlay_len = VROUTER_OVERLAY_LEN; int8_t *dmac; struct vr_bridge_entry *be; struct vr_nexthop *nh = NULL; struct vr_vrf_stats *stats; dmac = (int8_t *) pkt_data(pkt); if (pkt->vp_if->vif_flags & VIF_FLAG_MAC_LEARN) { if (vr_bridge_learn(router, pkt, fmd)) { return 0; } } pull_len = 0; if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6) || (pkt->vp_type == VP_TYPE_ARP)) { pull_len = pkt_get_network_header_off(pkt) - pkt_head_space(pkt); if (pull_len && !pkt_pull(pkt, pull_len)) { vr_pfree(pkt, VP_DROP_PULL); return 0; } } if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) { if (fmd->fmd_dscp < 0) { if (pkt->vp_type == VP_TYPE_IP) { fmd->fmd_dscp = vr_inet_get_tos((struct vr_ip *)pkt_network_header(pkt)); } else if (pkt->vp_type == VP_TYPE_IP6) { fmd->fmd_dscp = vr_inet6_get_tos((struct vr_ip6 *)pkt_network_header(pkt)); } } } else { if (fmd->fmd_dotonep < 0) { fmd->fmd_dotonep = vr_vlan_get_tos(pkt_data(pkt)); } } /* Do the bridge lookup for the packets not meant for "me" */ if (!fmd->fmd_to_me) { /* * If DHCP packet coming from VM, Trap it to Agent before doing the bridge * lookup itself */ if (vif_is_virtual(pkt->vp_if)) { if (pkt->vp_type == VP_TYPE_IP) l4_type = vr_ip_well_known_packet(pkt); else if (pkt->vp_type == VP_TYPE_IP6) l4_type = vr_ip6_well_known_packet(pkt); if (l4_type == L4_TYPE_DHCP_REQUEST) { if (pkt->vp_if->vif_flags & VIF_FLAG_DHCP_ENABLED) { vr_trap(pkt, fmd->fmd_dvrf, AGENT_TRAP_L3_PROTOCOLS, NULL); return 0; } } /* * Handle the unicast ARP, coming from VM, not * destined to us. Broadcast ARP requests would be handled * in L2 multicast nexthop. Multicast ARP on fabric * interface also would be handled in L2 multicast nexthop. * Unicast ARP packets on fabric interface would be handled * in plug routines of interface. */ if (!IS_MAC_BMCAST(dmac)) { handled = 0; if (pkt->vp_type == VP_TYPE_ARP) { handled = vr_arp_input(pkt, fmd, dmac); } else if (l4_type == L4_TYPE_NEIGHBOUR_SOLICITATION) { handled = vr_neighbor_input(pkt, fmd, dmac); } if (handled) return 0; } } be = bridge_lookup(dmac, fmd); if (be) nh = be->be_nh; if (!nh || nh->nh_type == NH_DISCARD) { /* If Flooding of unknown unicast not allowed, drop the packet */ if (!vr_unknown_uc_flood(pkt->vp_if, pkt->vp_nh) || IS_MAC_BMCAST(dmac)) { vr_pfree(pkt, VP_DROP_L2_NO_ROUTE); return 0; } be = bridge_lookup(vr_bcast_mac, fmd); nh = be->be_nh; if (!nh) { vr_pfree(pkt, VP_DROP_L2_NO_ROUTE); return 0; } stats = vr_inet_vrf_stats(fmd->fmd_dvrf, pkt->vp_cpu); if (stats) stats->vrf_uuc_floods++; /* Treat this unknown unicast packet as multicast */ pkt->vp_flags |= VP_FLAG_MULTICAST; } if (be) __sync_fetch_and_add(&be->be_packets, 1); if (nh->nh_type != NH_L2_RCV) overlay_len = VROUTER_L2_OVERLAY_LEN; } /* Adjust MSS for V4 and V6 packets */ if ((pkt->vp_type == VP_TYPE_IP) || (pkt->vp_type == VP_TYPE_IP6)) { if (vif_is_virtual(pkt->vp_if) && vr_from_vm_mss_adj && vr_pkt_from_vm_tcp_mss_adj) { if ((reason = vr_pkt_from_vm_tcp_mss_adj(pkt, overlay_len))) { vr_pfree(pkt, reason); return 0; } } if (fmd->fmd_to_me) { handled = vr_l3_input(pkt, fmd); if (!handled) { vr_pfree(pkt, VP_DROP_NOWHERE_TO_GO); } return 0; } } if (pull_len && !pkt_push(pkt, pull_len)) { vr_pfree(pkt, VP_DROP_PUSH); return 0; } nh_output(pkt, nh, fmd); return 0; }