/* Delete port to the bridge. */ lagopus_result_t bridge_port_delete(struct bridge_list *bridge_list, const char *name, uint32_t portid) { struct bridge *bridge; struct port *port; lagopus_result_t ret; flowdb_wrlock(NULL); /* Lookup bridge by name. */ bridge = bridge_lookup(bridge_list, name); if (bridge != NULL) { port = ifindex2port(bridge->ports, portid); if (port != NULL && port->bridge == bridge) { printf("Release port id %u from bridge %s\n", port->ifindex, bridge->name); vector_set_index(bridge->ports, port->ofp_port.port_no, NULL); send_port_status(port, OFPPR_DELETE); port->bridge = NULL; ret = LAGOPUS_RESULT_OK; } else { ret = LAGOPUS_RESULT_NOT_FOUND; } } else { ret = LAGOPUS_RESULT_NOT_FOUND; } flowdb_wrunlock(NULL); return ret; }
/* Add a new bridge. */ lagopus_result_t bridge_add(struct bridge_list *bridge_list, const char *name, uint64_t dpid) { struct bridge *bridge; /* Find bridge. */ bridge = bridge_lookup(bridge_list, name); if (bridge != NULL) { return LAGOPUS_RESULT_ALREADY_EXISTS; } /* Allocate a new bridge. */ bridge = bridge_alloc(name); if (bridge == NULL) { return LAGOPUS_RESULT_NO_MEMORY; } /* If given dpid is zero, generate random dpid value. */ if (dpid == 0) { dpid = bridge_dpid_generate(); } bridge->dpid = dpid; flowdb_wrlock(NULL); TAILQ_INSERT_TAIL(bridge_list, bridge, entry); flowdb_wrunlock(NULL); lagopus_msg_info("Bridge %s dpid:%0" PRIx64 " is added\n", name, dpid); return LAGOPUS_RESULT_OK; }
/* Set bridge dpid. */ lagopus_result_t dpmgr_bridge_dpid_set(struct dpmgr *dpmgr, const char *bridge_name, uint64_t dpid) { struct bridge *bridge; lagopus_result_t rv; FLOWDB_RWLOCK_WRLOCK(NULL); bridge = bridge_lookup(&dpmgr->bridge_list, bridge_name); if (bridge != NULL) { bridge->dpid = dpid; rv = LAGOPUS_RESULT_OK; } else { rv = LAGOPUS_RESULT_NOT_FOUND; } FLOWDB_RWLOCK_WRUNLOCK(NULL); return rv; }
/* Delete bridge. */ lagopus_result_t bridge_delete(struct bridge_list *bridge_list, const char *name) { struct bridge *bridge; lagopus_result_t ret; flowdb_wrlock(NULL); /* Lookup bridge by name. */ bridge = bridge_lookup(bridge_list, name); if (bridge != NULL) { TAILQ_REMOVE(bridge_list, bridge, entry); bridge_free(bridge); ret = LAGOPUS_RESULT_OK; } else { ret = LAGOPUS_RESULT_NOT_FOUND; } flowdb_wrunlock(NULL); /* not implemented yet. */ return ret; }
/* Add port to the bridge. */ lagopus_result_t bridge_port_add(struct bridge_list *bridge_list, const char *name, struct port *port) { struct bridge *bridge; lagopus_result_t ret; flowdb_wrlock(NULL); /* Lookup bridge by name. */ bridge = bridge_lookup(bridge_list, name); if (bridge != NULL) { /* Set port to the bridge's port vector. */ printf("Assigning port id %u to bridge %s\n", port->ifindex, bridge->name); vector_set_index(bridge->ports, port->ofp_port.port_no, port); port->bridge = bridge; send_port_status(port, OFPPR_ADD); ret = LAGOPUS_RESULT_OK; } else { ret = LAGOPUS_RESULT_NOT_FOUND; } flowdb_wrunlock(NULL); return ret; }
/* Lookup bridge. */ struct bridge * dpmgr_bridge_lookup(struct dpmgr *dpmgr, const char *bridge_name) { return bridge_lookup(&dpmgr->bridge_list, bridge_name); }
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; }
unsigned int vr_bridge_learn(struct vrouter *router, struct vr_packet *pkt, struct vr_forwarding_md *fmd) { int ret = 0, lock, valid_src; unsigned int trap_reason; bool trap = false; struct vr_eth *eth; struct vr_packet *pkt_c; struct vr_nexthop *nh = NULL; struct vr_bridge_entry *be; eth = (struct vr_eth *)pkt_data(pkt); if (!eth) return 0; if (IS_MAC_BMCAST(eth->eth_smac)) return 0; be = bridge_lookup(eth->eth_smac, fmd); if (be) { nh = be->be_nh; } if (!nh) { be = bridge_lookup((uint8_t *)vr_bcast_mac, fmd); if (be) { nh = be->be_nh; } if (!nh) return 0; lock = bridge_table_lock(pkt->vp_if, eth->eth_smac); if (lock < 0) return 0; be = bridge_add(0, fmd->fmd_dvrf, eth->eth_smac, nh->nh_id); bridge_table_unlock(pkt->vp_if, eth->eth_smac, lock); if (!be) return -ENOMEM; trap_reason = AGENT_TRAP_MAC_LEARN; trap = true; } else { if (!(be->be_flags & VR_BE_MAC_MOVED_FLAG) && (nh->nh_validate_src)) { valid_src = nh->nh_validate_src(pkt, nh, fmd, NULL); if (valid_src != NH_SOURCE_VALID) { ret = vr_bridge_set_route_flags(be, VR_BE_MAC_MOVED_FLAG); if (!ret) { /* trap the packet for mac move */ trap_reason = AGENT_TRAP_MAC_MOVE; trap = true; } ret = 0; } } } __sync_fetch_and_add(&be->be_packets, 1); if (trap) { pkt_c = pkt_cow(pkt, 0); if (!pkt_c) { pkt_c = pkt; ret = -ENOMEM; } vr_trap(pkt_c, fmd->fmd_dvrf, trap_reason, (void *)&be->be_hentry.hentry_index); } return ret; }