From 0f590a8a07c19d851259836004e21db0adaff2d3 Mon Sep 17 00:00:00 2001 From: Kazuya Goda Date: Fri, 2 Sep 2016 10:01:37 +0000 Subject: Add switch(4) support to ifconfig ok deraadt@ yasuoka@ reyk@ henning@ --- sys/net/if_bridge.c | 6 +-- sys/net/if_bridge.h | 18 +++++-- sys/net/if_switch.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++-- sys/net/switchofp.c | 64 ++++++++++++++++++++++-- sys/sys/sockio.h | 13 ++++- 5 files changed, 221 insertions(+), 17 deletions(-) (limited to 'sys') diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index ca79aaf0646..80c4b7e67ec 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bridge.c,v 1.282 2016/09/01 10:06:33 goda Exp $ */ +/* $OpenBSD: if_bridge.c,v 1.283 2016/09/02 10:01:36 goda Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -117,11 +117,7 @@ void bridge_span(struct bridge_softc *, struct mbuf *); void bridge_stop(struct bridge_softc *); void bridge_init(struct bridge_softc *); int bridge_bifconf(struct bridge_softc *, struct ifbifconf *); - int bridge_blocknonip(struct ether_header *, struct mbuf *); -struct mbuf *bridge_ip(struct bridge_softc *, int, struct ifnet *, - struct ether_header *, struct mbuf *m); -int bridge_ifenqueue(struct bridge_softc *, struct ifnet *, struct mbuf *); void bridge_ifinput(struct ifnet *, struct mbuf *); int bridge_dummy_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); diff --git a/sys/net/if_bridge.h b/sys/net/if_bridge.h index f7d8c97a974..df1a3b9f534 100644 --- a/sys/net/if_bridge.h +++ b/sys/net/if_bridge.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bridge.h,v 1.49 2016/09/01 10:06:33 goda Exp $ */ +/* $OpenBSD: if_bridge.h,v 1.50 2016/09/02 10:01:36 goda Exp $ */ /* * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) @@ -45,7 +45,7 @@ struct ifbreq { char ifbr_name[IFNAMSIZ]; /* bridge ifs name */ char ifbr_ifsname[IFNAMSIZ]; /* member ifs name */ u_int32_t ifbr_ifsflags; /* member ifs flags */ - u_int8_t ifbr_portno; /* member port number */ + u_int32_t ifbr_portno; /* member port number */ u_int8_t ifbr_state; /* member stp state */ u_int8_t ifbr_priority; /* member stp priority */ @@ -71,7 +71,8 @@ struct ifbreq { #define IFBIF_BSTP_PTP 0x0040 /* member stp ptp */ #define IFBIF_BSTP_AUTOPTP 0x0080 /* member stp autoptp enabled */ #define IFBIF_SPAN 0x0100 /* ifs is a span port (ro) */ -#define IFBIF_RO_MASK 0xff00 /* read only bits */ +#define IFBIF_LOCAL 0x1000 /* local port in switch(4) */ +#define IFBIF_RO_MASK 0x0f00 /* read only bits */ /* SIOCBRDGFLUSH */ #define IFBF_FLUSHDYN 0x0 /* flush dynamic addresses only */ @@ -152,6 +153,8 @@ struct ifbrparam { u_int8_t ifbrpu_maxage; /* max age (sec) */ u_int8_t ifbrpu_proto; /* bridge protocol */ u_int8_t ifbrpu_txhc; /* bpdu tx holdcount */ + u_int64_t ifbrpu_datapath; /* datapath-id */ + u_int32_t ifbrpu_maxgroup; /* group size */ } ifbrp_ifbrpu; }; #define ifbrp_csize ifbrp_ifbrpu.ifbrpu_csize @@ -162,6 +165,9 @@ struct ifbrparam { #define ifbrp_hellotime ifbrp_ifbrpu.ifbrpu_hellotime #define ifbrp_fwddelay ifbrp_ifbrpu.ifbrpu_fwddelay #define ifbrp_maxage ifbrp_ifbrpu.ifbrpu_maxage +#define ifbrp_datapath ifbrp_ifbrpu.ifbrpu_datapath +#define ifbrp_maxflow ifbrp_ifbrpu.ifbrpu_csize +#define ifbrp_maxgroup ifbrp_ifbrpu.ifbrpu_maxgroup /* Protocol versions */ #define BSTP_PROTO_ID 0x00 @@ -472,8 +478,12 @@ void bridge_timer(void *); u_int8_t bridge_filterrule(struct brl_head *, struct ether_header *, struct mbuf *); void bridge_flushrule(struct bridge_iflist *); -void bridge_fragment(struct bridge_softc *, struct ifnet *, + +struct mbuf *bridge_ip(struct bridge_softc *, int, struct ifnet *, + struct ether_header *, struct mbuf *); +void bridge_fragment(struct bridge_softc *, struct ifnet *, struct ether_header *, struct mbuf *); +int bridge_ifenqueue(struct bridge_softc *, struct ifnet *, struct mbuf *); #endif /* _KERNEL */ #endif /* _NET_IF_BRIDGE_H_ */ diff --git a/sys/net/if_switch.c b/sys/net/if_switch.c index b8c3529cee7..8f481583981 100644 --- a/sys/net/if_switch.c +++ b/sys/net/if_switch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_switch.c,v 1.1 2016/09/01 10:06:33 goda Exp $ */ +/* $OpenBSD: if_switch.c,v 1.2 2016/09/02 10:01:36 goda Exp $ */ /* * Copyright (c) 2016 Kazuya GODA @@ -120,6 +120,9 @@ struct mbuf struct mbuf *switch_flow_classifier_ether(struct mbuf *, int *, struct switch_flow_classify *); +struct mbuf + *switch_flow_classifier_tunnel(struct mbuf *, int *, + struct switch_flow_classify *); struct mbuf *switch_flow_classifier(struct mbuf *, uint32_t, struct switch_flow_classify *); @@ -212,6 +215,8 @@ switch_clone_destroy(struct ifnet *ifp) TAILQ_FOREACH_SAFE(swpo, &sc->sc_swpo_list, swpo_list_next, tp) { if ((ifs = if_get(swpo->swpo_ifindex)) != NULL) { + if (swpo->swpo_flags & IFBIF_LOCAL) + switch_port_unset_local(sc, swpo); ifs->if_switchport = NULL; ifpromisc(ifs, 0); if_ih_remove(ifs, switch_input, NULL); @@ -306,6 +311,99 @@ discard: sc->sc_if.if_oerrors++; } +int +switch_port_set_local(struct switch_softc *sc, struct switch_port *swpo) +{ + struct switch_port *tswpo; + struct ifreq ifreq; + struct ifnet *ifs; + int error = 0, re_up = 0; + + /* + * Only one local interface can exist per switch device. + */ + TAILQ_FOREACH(tswpo, &sc->sc_swpo_list, swpo_list_next) { + if (tswpo->swpo_flags & IFBIF_LOCAL) + return (EEXIST); + } + + ifs = if_get(swpo->swpo_ifindex); + if (ifs == NULL) + return (ENOENT); + + if (ifs->if_flags & IFF_UP) { + re_up = 1; + memset(&ifreq, 0, sizeof(ifreq)); + strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ); + ifs->if_flags &= ~IFF_UP; + ifreq.ifr_flags = ifs->if_flags; + error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq); + if (error) + goto error; + } + + swpo->swpo_flags |= IFBIF_LOCAL; + swpo->swpo_port_no = OFP_PORT_LOCAL; + swpo->swop_bk_start = ifs->if_start; + ifs->if_start = switch_port_ifb_start; + + if (re_up) { + memset(&ifreq, 0, sizeof(ifreq)); + strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ); + ifs->if_flags &= IFF_UP; + ifreq.ifr_flags = ifs->if_flags; + error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq); + if (error) + goto error; + } + + error: + if_put(ifs); + return (error); +} + +int +switch_port_unset_local(struct switch_softc *sc, struct switch_port *swpo) +{ + struct ifreq ifreq; + struct ifnet *ifs; + int error = 0, re_up = 0; + + ifs = if_get(swpo->swpo_ifindex); + if (ifs == NULL) + return (ENOENT); + + if (ifs->if_flags & IFF_UP) { + re_up = 1; + memset(&ifreq, 0, sizeof(ifreq)); + strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ); + ifs->if_flags &= ~IFF_UP; + ifreq.ifr_flags = ifs->if_flags; + error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq); + if (error) + goto error; + } + + swpo->swpo_flags &= ~IFBIF_LOCAL; + swpo->swpo_port_no = swofp_assign_portno(sc, ifs->if_index); + ifs->if_start = swpo->swop_bk_start; + swpo->swop_bk_start = NULL; + + if (re_up) { + memset(&ifreq, 0, sizeof(ifreq)); + strlcpy(ifreq.ifr_name, ifs->if_xname, IFNAMSIZ); + ifs->if_flags &= IFF_UP; + ifreq.ifr_flags = ifs->if_flags; + error = (*ifs->if_ioctl)(ifs, SIOCSIFFLAGS, (caddr_t)&ifreq); + if (error) + goto error; + } + + error: + if_put(ifs); + return (error); +} + int switch_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) { @@ -335,6 +433,24 @@ switch_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) case SIOCBRDGIFS: error = switch_port_list(sc, (struct ifbifconf *)data); break; + case SIOCBRDGADDL: + if ((error = suser(curproc, 0)) != 0) + break; + error = switch_port_add(sc, (struct ifbreq *)data); + if (error && error != EEXIST) + break; + ifs = ifunit(breq->ifbr_ifsname); + if (ifs == NULL) { + error = ENOENT; + break; + } + swpo = (struct switch_port *)ifs->if_switchport; + if (swpo == NULL || swpo->swpo_switch != sc) { + error = ESRCH; + break; + } + error = switch_port_set_local(sc, swpo); + break; case SIOCBRDGGIFFLGS: ifs = ifunit(breq->ifbr_ifsname); if (ifs == NULL) { @@ -381,6 +497,13 @@ switch_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) brop->ifbop_last_tc_time.tv_sec = bs->bs_last_tc_time.tv_sec; brop->ifbop_last_tc_time.tv_usec = bs->bs_last_tc_time.tv_usec; break; + case SIOCSWGDPID: + case SIOCSWSDPID: + case SIOCSWGFLOWMAX: + case SIOCSWGMAXGROUP: + case SIOCSWSPORTNO: + error = swofp_ioctl(ifp, cmd, data); + break; default: error = ENOTTY; break; @@ -521,6 +644,8 @@ switch_port_del(struct switch_softc *sc, struct ifbreq *req) } if (swpo) { + if (swpo->swpo_flags & IFBIF_LOCAL) + switch_port_unset_local(sc, swpo); ifs->if_switchport = NULL; ifpromisc(ifs, 0); if_ih_remove(ifs, switch_input, NULL); @@ -661,11 +786,17 @@ switch_port_egress(struct switch_softc *sc, struct switch_fwdp_queue *fwdp_q, len += ETHER_VLAN_ENCAP_LEN; #endif - if (((len - ETHER_HDR_LEN) > dst_if->if_mtu)) + /* + * Only if egress port has local port capabilities, it doesn't + * need fragment because a frame sends up local network stack. + */ + if (!(swpo->swpo_flags & IFBIF_LOCAL) && + ((len - ETHER_HDR_LEN) > dst_if->if_mtu)) bridge_fragment((struct bridge_softc *)sc, dst_if, &eh, mc); else - switch_ifenqueue(sc, dst_if, mc, 0); + switch_ifenqueue(sc, dst_if, mc, + (swpo->swpo_flags & IFBIF_LOCAL)); out: if_put(dst_if); diff --git a/sys/net/switchofp.c b/sys/net/switchofp.c index cd8e7408e96..6b9102cf59e 100644 --- a/sys/net/switchofp.c +++ b/sys/net/switchofp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: switchofp.c,v 1.1 2016/09/01 10:06:33 goda Exp $ */ +/* $OpenBSD: switchofp.c,v 1.2 2016/09/02 10:01:36 goda Exp $ */ /* * Copyright (c) 2016 Kazuya GODA @@ -1024,9 +1024,53 @@ swofp_assign_portno(struct switch_softc *sc, uint32_t req) int swofp_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data) { + struct switch_softc *sc = ifp->if_softc; + struct swofp_ofs *swofs = sc->sc_ofs; + struct ifbrparam *bparam = (struct ifbrparam *)data; + struct ifbreq *breq = (struct ifbreq *)data; + struct switch_port *swpo; + struct ifnet *ifs; int error = 0; switch (cmd) { + case SIOCSWGDPID: + memcpy(&bparam->ifbrp_datapath, &swofs->swofs_datapath_id, + sizeof(uint64_t)); + break; + case SIOCSWSDPID: + if ((error = suser(curproc, 0)) != 0) + break; + memcpy(&swofs->swofs_datapath_id, &bparam->ifbrp_datapath, + sizeof(uint64_t)); + break; + case SIOCSWGFLOWMAX: + bparam->ifbrp_maxflow = swofs->swofs_flow_max_entry; + break; + case SIOCSWGMAXGROUP: + bparam->ifbrp_maxgroup = swofs->swofs_group_table_num; + break; + case SIOCSWSPORTNO: + if ((error = suser(curproc, 0)) != 0) + break; + + if (breq->ifbr_portno >= OFP_PORT_MAX) + return (EINVAL); + + if ((ifs = ifunit(breq->ifbr_ifsname)) == NULL) + return (ENOENT); + + if (ifs->if_switchport == NULL) + return (ENOENT); + + TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { + if (swpo->swpo_port_no == breq->ifbr_portno) + return (EEXIST); + } + + swpo = (struct switch_port *)ifs->if_switchport; + swpo->swpo_port_no = breq->ifbr_portno; + + break; default: error = ENOTTY; break; @@ -3161,7 +3205,13 @@ swofp_action_output(struct switch_softc *sc, struct mbuf *m, /* no support yet */ break; case OFP_PORT_LOCAL: - /* no support yet */ + TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { + if (swpo->swpo_flags & IFBIF_LOCAL) { + TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo, + swpo_fwdp_next); + break; + } + } break; default: TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) { @@ -5558,7 +5608,10 @@ swofp_mp_recv_port_stats(struct switch_softc *sc, struct mbuf *m) if (ifs == NULL) continue; - postat.pt_port_no = htonl(swpo->swpo_port_no); + if (swpo->swpo_flags & IFBIF_LOCAL) + postat.pt_port_no = htonl(OFP_PORT_LOCAL); + else + postat.pt_port_no = htonl(swpo->swpo_port_no); postat.pt_rx_packets = htobe64(ifs->if_ipackets); postat.pt_tx_packets = htobe64(ifs->if_opackets); postat.pt_rx_bytes = htobe64(ifs->if_obytes); @@ -5888,7 +5941,10 @@ swofp_mp_recv_port_desc(struct switch_softc *sc, struct mbuf *m) if (ifs == NULL) continue; - swp.swp_number = htonl(swpo->swpo_port_no); + if (swpo->swpo_flags & IFBIF_LOCAL) + swp.swp_number = htonl(OFP_PORT_LOCAL); + else + swp.swp_number = htonl(swpo->swpo_port_no); memcpy(swp.swp_macaddr, ((struct arpcom *)ifs)->ac_enaddr, ETHER_ADDR_LEN); diff --git a/sys/sys/sockio.h b/sys/sys/sockio.h index 6ccf4e62b71..28202860775 100644 --- a/sys/sys/sockio.h +++ b/sys/sys/sockio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sockio.h,v 1.67 2016/08/28 07:22:11 reyk Exp $ */ +/* $OpenBSD: sockio.h,v 1.68 2016/09/02 10:01:36 goda Exp $ */ /* $NetBSD: sockio.h,v 1.5 1995/08/23 00:40:47 thorpej Exp $ */ /*- @@ -102,6 +102,7 @@ #define SIOCBRDGGTO _IOWR('i', 70, struct ifbrparam)/* cache timeout */ #define SIOCBRDGDADDR _IOW('i', 71, struct ifbareq) /* delete addr */ #define SIOCBRDGFLUSH _IOW('i', 72, struct ifbreq) /* flush addr cache */ +#define SIOCBRDGADDL _IOW('i', 73, struct ifbreq) /* add local port */ #define SIOCBRDGARL _IOW('i', 77, struct ifbrlreq) /* add bridge rule */ #define SIOCBRDGFRL _IOW('i', 78, struct ifbrlreq) /* flush brdg rules */ @@ -122,6 +123,16 @@ #define SIOCBRDGSPROTO _IOW('i', 90, struct ifbrparam)/* set protocol */ #define SIOCBRDGS +/* Following ioctls for switch(4) has compatibility to bridge(4) */ +#define SIOCSWSFLOWMAX SIOCBRDGSCACHE /* set max flow per table */ +#define SIOCSWGFLOWMAX SIOCBRDGGCACHE /* get max flow per table */ + +#define SIOCSWGDPID _IOWR('i', 91, struct ifbrparam)/* set datapath id */ +#define SIOCSWSDPID _IOW('i', 91, struct ifbrparam)/* get datapath id */ +#define SIOCSWGMAXGROUP _IOWR('i', 92, struct ifbrparam)/* get max groups */ +#define SIOCSWSMAXGROUP _IOW('i', 92, struct ifbrparam)/* set max groups */ +#define SIOCSWSPORTNO _IOWR('i', 93, struct ifbreq) /* set port number */ + #define SIOCSIFMTU _IOW('i', 127, struct ifreq) /* set ifnet mtu */ #define SIOCGIFMTU _IOWR('i', 126, struct ifreq) /* get ifnet mtu */ #define SIOCSIFASYNCMAP _IOW('i', 125, struct ifreq) /* set ppp asyncmap */ -- cgit v1.2.3