2019-01-01 08:23:01 +00:00
//
2019-01-09 16:54:15 +00:00
// Copyright 2015 flannel authors
2019-01-01 08:23:01 +00:00
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package flannel
import (
"fmt"
"net"
"os"
"path/filepath"
"sync"
2023-02-06 15:17:37 +00:00
"github.com/flannel-io/flannel/pkg/backend"
2021-03-18 22:40:29 +00:00
"github.com/flannel-io/flannel/pkg/ip"
2023-02-06 15:17:37 +00:00
"github.com/flannel-io/flannel/pkg/iptables"
"github.com/flannel-io/flannel/pkg/subnet/kube"
2023-08-31 15:39:33 +00:00
"github.com/pkg/errors"
2021-12-21 13:32:34 +00:00
"github.com/sirupsen/logrus"
2019-01-01 08:23:01 +00:00
"golang.org/x/net/context"
// Backends need to be imported for their init() to get executed and them to register
2023-02-06 15:17:37 +00:00
_ "github.com/flannel-io/flannel/pkg/backend/extension"
_ "github.com/flannel-io/flannel/pkg/backend/hostgw"
_ "github.com/flannel-io/flannel/pkg/backend/ipsec"
_ "github.com/flannel-io/flannel/pkg/backend/vxlan"
_ "github.com/flannel-io/flannel/pkg/backend/wireguard"
2019-01-01 08:23:01 +00:00
)
const (
subnetFile = "/run/flannel/subnet.env"
)
2022-09-26 12:56:55 +00:00
var (
FlannelBaseAnnotation = "flannel.alpha.coreos.com"
FlannelExternalIPv4Annotation = FlannelBaseAnnotation + "/public-ip-overwrite"
FlannelExternalIPv6Annotation = FlannelBaseAnnotation + "/public-ipv6-overwrite"
)
2023-02-06 15:35:18 +00:00
func flannel ( ctx context . Context , flannelIface * net . Interface , flannelConf , kubeConfigFile string , flannelIPv6Masq bool , multiClusterCIDR bool , netMode int ) error {
2021-08-17 09:27:54 +00:00
extIface , err := LookupExtInterface ( flannelIface , netMode )
2019-01-01 08:23:01 +00:00
if err != nil {
2023-08-31 15:39:33 +00:00
return errors . Wrap ( err , "failed to find the interface" )
2019-01-01 08:23:01 +00:00
}
2023-02-06 15:17:37 +00:00
sm , err := kube . NewSubnetManager ( ctx ,
"" ,
kubeConfigFile ,
FlannelBaseAnnotation ,
flannelConf ,
false ,
2023-02-06 15:35:18 +00:00
multiClusterCIDR )
2019-01-01 08:23:01 +00:00
if err != nil {
2023-08-31 15:39:33 +00:00
return errors . Wrap ( err , "failed to create the SubnetManager" )
2019-01-01 08:23:01 +00:00
}
config , err := sm . GetNetworkConfig ( ctx )
if err != nil {
2023-08-31 15:39:33 +00:00
return errors . Wrap ( err , "failed to get the network config" )
2019-01-01 08:23:01 +00:00
}
// Create a backend manager then use it to create the backend and register the network with it.
bm := backend . NewManager ( ctx , sm , extIface )
be , err := bm . GetBackend ( config . BackendType )
if err != nil {
2023-08-31 15:39:33 +00:00
return errors . Wrap ( err , "failed to create the flannel backend" )
2019-01-01 08:23:01 +00:00
}
2021-03-18 22:40:29 +00:00
bn , err := be . RegisterNetwork ( ctx , & sync . WaitGroup { } , config )
2019-01-01 08:23:01 +00:00
if err != nil {
2023-08-31 15:39:33 +00:00
return errors . Wrap ( err , "failed to register flannel network" )
2019-01-01 08:23:01 +00:00
}
2022-03-04 17:06:29 +00:00
if netMode == ( ipv4 + ipv6 ) || netMode == ipv4 {
2023-02-06 15:17:37 +00:00
net , err := config . GetFlannelNetwork ( & bn . Lease ( ) . Subnet )
if err != nil {
2023-08-31 15:39:33 +00:00
return errors . Wrap ( err , "failed to get flannel network details" )
2023-02-06 15:17:37 +00:00
}
iptables . CreateIP4Chain ( "nat" , "FLANNEL-POSTRTG" )
iptables . CreateIP4Chain ( "filter" , "FLANNEL-FWD" )
getMasqRules := func ( ) [ ] iptables . IPTablesRule {
if config . HasNetworks ( ) {
return iptables . MasqRules ( config . Networks , bn . Lease ( ) )
}
return iptables . MasqRules ( [ ] ip . IP4Net { config . Network } , bn . Lease ( ) )
}
getFwdRules := func ( ) [ ] iptables . IPTablesRule {
return iptables . ForwardRules ( net . String ( ) )
}
go iptables . SetupAndEnsureIP4Tables ( getMasqRules , 60 )
go iptables . SetupAndEnsureIP4Tables ( getFwdRules , 50 )
2022-03-04 17:06:29 +00:00
}
2019-01-01 08:23:01 +00:00
2023-02-06 15:17:37 +00:00
if config . IPv6Network . String ( ) != emptyIPv6Network {
ip6net , err := config . GetFlannelIPv6Network ( & bn . Lease ( ) . IPv6Subnet )
if err != nil {
2023-08-31 15:39:33 +00:00
return errors . Wrap ( err , "failed to get ipv6 flannel network details" )
2023-02-06 15:17:37 +00:00
}
if flannelIPv6Masq {
logrus . Debugf ( "Creating IPv6 masquerading iptables rules for %s network" , config . IPv6Network . String ( ) )
iptables . CreateIP6Chain ( "nat" , "FLANNEL-POSTRTG" )
getRules := func ( ) [ ] iptables . IPTablesRule {
if config . HasIPv6Networks ( ) {
return iptables . MasqIP6Rules ( config . IPv6Networks , bn . Lease ( ) )
}
return iptables . MasqIP6Rules ( [ ] ip . IP6Net { config . IPv6Network } , bn . Lease ( ) )
}
go iptables . SetupAndEnsureIP6Tables ( getRules , 60 )
}
iptables . CreateIP6Chain ( "filter" , "FLANNEL-FWD" )
getRules := func ( ) [ ] iptables . IPTablesRule {
return iptables . ForwardRules ( ip6net . String ( ) )
}
go iptables . SetupAndEnsureIP6Tables ( getRules , 50 )
2022-01-12 16:09:38 +00:00
}
2022-03-04 17:06:29 +00:00
if err := WriteSubnetFile ( subnetFile , config . Network , config . IPv6Network , true , bn , netMode ) ; err != nil {
2019-01-01 08:23:01 +00:00
// Continue, even though it failed.
2021-12-21 13:32:34 +00:00
logrus . Warningf ( "Failed to write flannel subnet file: %s" , err )
2019-01-01 08:23:01 +00:00
} else {
2021-12-21 13:32:34 +00:00
logrus . Infof ( "Wrote flannel subnet file to %s" , subnetFile )
2019-01-01 08:23:01 +00:00
}
// Start "Running" the backend network. This will block until the context is done so run in another goroutine.
2021-12-21 13:32:34 +00:00
logrus . Info ( "Running flannel backend." )
2019-01-01 08:23:01 +00:00
bn . Run ( ctx )
return nil
}
2021-08-17 09:27:54 +00:00
func LookupExtInterface ( iface * net . Interface , netMode int ) ( * backend . ExternalInterface , error ) {
2022-03-02 14:01:25 +00:00
var ifaceAddr [ ] net . IP
var ifacev6Addr [ ] net . IP
2019-01-01 08:23:01 +00:00
var err error
2019-03-19 23:28:43 +00:00
if iface == nil {
2021-12-21 13:32:34 +00:00
logrus . Debug ( "No interface defined for flannel in the config. Fetching the default gateway interface" )
2022-03-04 17:06:29 +00:00
if netMode == ipv4 || netMode == ( ipv4 + ipv6 ) {
if iface , err = ip . GetDefaultGatewayInterface ( ) ; err != nil {
2023-08-31 15:39:33 +00:00
return nil , errors . Wrap ( err , "failed to get default interface" )
2022-03-04 17:06:29 +00:00
}
} else {
if iface , err = ip . GetDefaultV6GatewayInterface ( ) ; err != nil {
2023-08-31 15:39:33 +00:00
return nil , errors . Wrap ( err , "failed to get default interface" )
2022-03-04 17:06:29 +00:00
}
2019-03-19 23:28:43 +00:00
}
2019-01-01 08:23:01 +00:00
}
2021-12-21 13:32:34 +00:00
logrus . Debugf ( "The interface %s will be used by flannel" , iface . Name )
2019-01-01 08:23:01 +00:00
2022-03-08 08:34:25 +00:00
switch netMode {
case ipv4 :
2022-03-07 10:05:08 +00:00
ifaceAddr , err = ip . GetInterfaceIP4Addrs ( iface )
if err != nil {
2023-08-31 15:39:33 +00:00
return nil , errors . Wrap ( err , "failed to find IPv4 address for interface" )
2022-03-07 10:05:08 +00:00
}
logrus . Infof ( "The interface %s with ipv4 address %s will be used by flannel" , iface . Name , ifaceAddr [ 0 ] )
2022-03-08 08:34:25 +00:00
ifacev6Addr = append ( ifacev6Addr , nil )
case ipv6 :
ifacev6Addr , err = ip . GetInterfaceIP6Addrs ( iface )
if err != nil {
2023-08-31 15:39:33 +00:00
return nil , errors . Wrap ( err , "failed to find IPv6 address for interface" )
2022-03-08 08:34:25 +00:00
}
2022-03-08 08:42:25 +00:00
logrus . Infof ( "The interface %s with ipv6 address %s will be used by flannel" , iface . Name , ifacev6Addr [ 0 ] )
2022-03-07 10:05:08 +00:00
ifaceAddr = append ( ifaceAddr , nil )
2022-03-08 08:34:25 +00:00
case ( ipv4 + ipv6 ) :
ifaceAddr , err = ip . GetInterfaceIP4Addrs ( iface )
if err != nil {
return nil , fmt . Errorf ( "failed to find IPv4 address for interface %s" , iface . Name )
}
2022-03-02 14:01:25 +00:00
ifacev6Addr , err = ip . GetInterfaceIP6Addrs ( iface )
2021-08-17 09:27:54 +00:00
if err != nil {
return nil , fmt . Errorf ( "failed to find IPv6 address for interface %s" , iface . Name )
}
2023-11-08 08:44:38 +00:00
logrus . Infof ( "Using dual-stack mode. The interface %s with ipv4 address %s and ipv6 address %s will be used by flannel" , iface . Name , ifaceAddr [ 0 ] , ifacev6Addr [ 0 ] )
2022-03-08 08:34:25 +00:00
default :
ifaceAddr = append ( ifaceAddr , nil )
2022-03-07 10:05:08 +00:00
ifacev6Addr = append ( ifacev6Addr , nil )
2021-08-17 09:27:54 +00:00
}
2022-03-08 08:34:25 +00:00
2019-01-01 08:23:01 +00:00
if iface . MTU == 0 {
2022-03-07 10:05:08 +00:00
return nil , fmt . Errorf ( "failed to determine MTU for %s interface" , iface . Name )
2019-01-01 08:23:01 +00:00
}
return & backend . ExternalInterface {
2021-08-17 09:27:54 +00:00
Iface : iface ,
2022-03-02 14:01:25 +00:00
IfaceAddr : ifaceAddr [ 0 ] ,
IfaceV6Addr : ifacev6Addr [ 0 ] ,
ExtAddr : ifaceAddr [ 0 ] ,
ExtV6Addr : ifacev6Addr [ 0 ] ,
2019-01-01 08:23:01 +00:00
} , nil
}
2022-03-04 17:06:29 +00:00
func WriteSubnetFile ( path string , nw ip . IP4Net , nwv6 ip . IP6Net , ipMasq bool , bn backend . Network , netMode int ) error {
2019-01-01 08:23:01 +00:00
dir , name := filepath . Split ( path )
os . MkdirAll ( dir , 0755 )
tempFile := filepath . Join ( dir , "." + name )
f , err := os . Create ( tempFile )
if err != nil {
return err
}
// Write out the first usable IP by incrementing
// sn.IP by one
sn := bn . Lease ( ) . Subnet
2019-03-25 04:54:52 +00:00
sn . IP ++
2022-03-04 17:06:29 +00:00
if netMode == ipv4 || netMode == ( ipv4 + ipv6 ) {
fmt . Fprintf ( f , "FLANNEL_NETWORK=%s\n" , nw )
fmt . Fprintf ( f , "FLANNEL_SUBNET=%s\n" , sn )
}
2021-08-17 09:27:54 +00:00
if nwv6 . String ( ) != emptyIPv6Network {
snv6 := bn . Lease ( ) . IPv6Subnet
snv6 . IncrementIP ( )
fmt . Fprintf ( f , "FLANNEL_IPV6_NETWORK=%s\n" , nwv6 )
fmt . Fprintf ( f , "FLANNEL_IPV6_SUBNET=%s\n" , snv6 )
}
2019-01-01 08:23:01 +00:00
fmt . Fprintf ( f , "FLANNEL_MTU=%d\n" , bn . MTU ( ) )
_ , err = fmt . Fprintf ( f , "FLANNEL_IPMASQ=%v\n" , ipMasq )
f . Close ( )
if err != nil {
return err
}
// rename(2) the temporary file to the desired location so that it becomes
// atomically visible with the contents
return os . Rename ( tempFile , path )
//TODO - is this safe? What if it's not on the same FS?
}