mirror of https://github.com/jetkvm/kvm.git
show flags on ipv6 network card
This commit is contained in:
parent
a9cd36c5fb
commit
6ff4f37a36
|
|
@ -9,5 +9,6 @@
|
|||
"synctrace"
|
||||
]
|
||||
},
|
||||
"git.ignoreLimitWarning": true
|
||||
"git.ignoreLimitWarning": true,
|
||||
"cmake.sourceDirectory": "/workspaces/kvm-static-ip/internal/native/cgo"
|
||||
}
|
||||
|
|
@ -1,20 +1,36 @@
|
|||
package types
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// RpcIPv6Address is the RPC representation of an IPv6 address
|
||||
type RpcIPv6Address struct {
|
||||
Address string `json:"address"`
|
||||
Prefix string `json:"prefix"`
|
||||
ValidLifetime *time.Time `json:"valid_lifetime"`
|
||||
PreferredLifetime *time.Time `json:"preferred_lifetime"`
|
||||
Scope int `json:"scope"`
|
||||
Flags int `json:"flags"`
|
||||
FlagSecondary bool `json:"flag_secondary"`
|
||||
FlagPermanent bool `json:"flag_permanent"`
|
||||
FlagTemporary bool `json:"flag_temporary"`
|
||||
FlagStablePrivacy bool `json:"flag_stable_privacy"`
|
||||
FlagDeprecated bool `json:"flag_deprecated"`
|
||||
FlagOptimistic bool `json:"flag_optimistic"`
|
||||
FlagDADFailed bool `json:"flag_dad_failed"`
|
||||
FlagTentative bool `json:"flag_tentative"`
|
||||
}
|
||||
|
||||
// RpcInterfaceState is the RPC representation of an interface state
|
||||
type RpcInterfaceState struct {
|
||||
InterfaceState
|
||||
IPv6Addresses []RpcIPv6Address `json:"ipv6_addresses"`
|
||||
}
|
||||
|
||||
// ToRpcInterfaceState converts an InterfaceState to a RpcInterfaceState
|
||||
func (s *InterfaceState) ToRpcInterfaceState() *RpcInterfaceState {
|
||||
addrs := make([]RpcIPv6Address, len(s.IPv6Addresses))
|
||||
for i, addr := range s.IPv6Addresses {
|
||||
|
|
@ -24,6 +40,15 @@ func (s *InterfaceState) ToRpcInterfaceState() *RpcInterfaceState {
|
|||
ValidLifetime: addr.ValidLifetime,
|
||||
PreferredLifetime: addr.PreferredLifetime,
|
||||
Scope: addr.Scope,
|
||||
Flags: addr.Flags,
|
||||
FlagSecondary: addr.Flags&unix.IFA_F_SECONDARY != 0,
|
||||
FlagPermanent: addr.Flags&unix.IFA_F_PERMANENT != 0,
|
||||
FlagTemporary: addr.Flags&unix.IFA_F_TEMPORARY != 0,
|
||||
FlagStablePrivacy: addr.Flags&unix.IFA_F_STABLE_PRIVACY != 0,
|
||||
FlagDeprecated: addr.Flags&unix.IFA_F_DEPRECATED != 0,
|
||||
FlagOptimistic: addr.Flags&unix.IFA_F_OPTIMISTIC != 0,
|
||||
FlagDADFailed: addr.Flags&unix.IFA_F_DADFAILED != 0,
|
||||
FlagTentative: addr.Flags&unix.IFA_F_TENTATIVE != 0,
|
||||
}
|
||||
}
|
||||
return &RpcInterfaceState{
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ type IPv6Address struct {
|
|||
Prefix net.IPNet `json:"prefix"`
|
||||
ValidLifetime *time.Time `json:"valid_lifetime"`
|
||||
PreferredLifetime *time.Time `json:"preferred_lifetime"`
|
||||
Flags int `json:"flags"`
|
||||
Scope int `json:"scope"`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ func (im *InterfaceManager) updateInterfaceStateAddresses(nl *link.Link) (bool,
|
|||
Address: addr.IP,
|
||||
Prefix: *addr.IPNet,
|
||||
Scope: addr.Scope,
|
||||
Flags: addr.Flags,
|
||||
ValidLifetime: lifetimeToTime(addr.ValidLft),
|
||||
PreferredLifetime: lifetimeToTime(addr.PreferedLft),
|
||||
})
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ type Client struct {
|
|||
var (
|
||||
defaultTimerDuration = 1 * time.Second
|
||||
defaultLinkUpTimeout = 30 * time.Second
|
||||
maxRenewalAttemptDuration = 2 * time.Hour
|
||||
)
|
||||
|
||||
// NewClient creates a new DHCP client for the given interface.
|
||||
|
|
@ -155,10 +156,21 @@ func resetTimer(t *time.Timer, l *zerolog.Logger) {
|
|||
t.Reset(defaultTimerDuration)
|
||||
}
|
||||
|
||||
func getRenewalTime(lease *Lease) time.Duration {
|
||||
if lease.RenewalTime <= 0 || lease.LeaseTime > maxRenewalAttemptDuration/2 {
|
||||
return maxRenewalAttemptDuration
|
||||
}
|
||||
|
||||
return lease.RenewalTime
|
||||
}
|
||||
|
||||
func (c *Client) requestLoop(t *time.Timer, family int, ifname string) {
|
||||
l := c.l.With().Str("interface", ifname).Int("family", family).Logger()
|
||||
for range t.C {
|
||||
l.Info().Msg("requesting lease")
|
||||
|
||||
if _, err := c.ensureInterfaceUp(ifname); err != nil {
|
||||
c.l.Error().Err(err).Msg("failed to ensure interface up")
|
||||
l.Error().Err(err).Msg("failed to ensure interface up")
|
||||
resetTimer(t, c.l)
|
||||
continue
|
||||
}
|
||||
|
|
@ -174,12 +186,22 @@ func (c *Client) requestLoop(t *time.Timer, family int, ifname string) {
|
|||
lease, err = c.requestLease6(ifname)
|
||||
}
|
||||
if err != nil {
|
||||
c.l.Error().Err(err).Msg("failed to request lease")
|
||||
l.Error().Err(err).Msg("failed to request lease")
|
||||
resetTimer(t, c.l)
|
||||
continue
|
||||
}
|
||||
|
||||
c.handleLeaseChange(lease)
|
||||
|
||||
nextRenewal := getRenewalTime(lease)
|
||||
|
||||
l.Info().
|
||||
Dur("nextRenewal", nextRenewal).
|
||||
Dur("leaseTime", lease.LeaseTime).
|
||||
Dur("rebindingTime", lease.RebindingTime).
|
||||
Msg("sleeping until next renewal")
|
||||
|
||||
t.Reset(nextRenewal)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -262,25 +284,9 @@ func (c *Client) handleLeaseChange(lease *Lease) {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *Client) doRenewLoop() {
|
||||
timer := time.NewTimer(time.Duration(c.currentLease4.RenewalTime) * time.Second)
|
||||
defer timer.Stop()
|
||||
|
||||
for range timer.C {
|
||||
c.renew()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) renew() {
|
||||
// for lease := range c.sendRequests(c.cfg.IPv4, c.cfg.IPv6) {
|
||||
// if lease, ok := lease.(*Lease); ok {
|
||||
// c.handleLeaseChange(lease)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
func (c *Client) Renew() error {
|
||||
go c.renew()
|
||||
c.timer4.Reset(defaultTimerDuration)
|
||||
c.timer6.Reset(defaultTimerDuration)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -304,9 +310,11 @@ func (c *Client) SetIPv4(ipv4 bool) {
|
|||
c.lease4Mu.Lock()
|
||||
c.currentLease4 = nil
|
||||
c.lease4Mu.Unlock()
|
||||
}
|
||||
|
||||
c.timer4.Stop()
|
||||
}
|
||||
|
||||
c.timer4.Reset(defaultTimerDuration)
|
||||
}
|
||||
|
||||
func (c *Client) SetIPv6(ipv6 bool) {
|
||||
|
|
@ -323,10 +331,12 @@ func (c *Client) SetIPv6(ipv6 bool) {
|
|||
if !ipv6 {
|
||||
c.lease6Mu.Lock()
|
||||
c.currentLease6 = nil
|
||||
c.lease4Mu.Unlock()
|
||||
}
|
||||
c.lease6Mu.Unlock()
|
||||
|
||||
c.timer6.Stop()
|
||||
}
|
||||
|
||||
c.timer6.Reset(defaultTimerDuration)
|
||||
}
|
||||
|
||||
func (c *Client) Start() error {
|
||||
|
|
|
|||
|
|
@ -47,9 +47,20 @@ func (c *Client) requestLease4(ifname string) (*Lease, error) {
|
|||
}
|
||||
|
||||
l.Info().Msg("attempting to get DHCPv4 lease")
|
||||
lease, err := client.Request(c.ctx, reqmods...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
var (
|
||||
lease *nclient4.Lease
|
||||
reqErr error
|
||||
)
|
||||
if c.currentLease4 != nil {
|
||||
l.Info().Msg("current lease is not nil, renewing")
|
||||
lease, reqErr = client.Renew(c.ctx, c.currentLease4.p4, reqmods...)
|
||||
} else {
|
||||
l.Info().Msg("current lease is nil, requesting new lease")
|
||||
lease, reqErr = client.Request(c.ctx, reqmods...)
|
||||
}
|
||||
|
||||
if reqErr != nil {
|
||||
return nil, reqErr
|
||||
}
|
||||
|
||||
if lease == nil || lease.ACK == nil {
|
||||
|
|
|
|||
|
|
@ -58,9 +58,15 @@ func compareIPv6AddressSlices(a, b []types.IPv6Address) bool {
|
|||
if a[i].Address.String() != b[i].Address.String() {
|
||||
return false
|
||||
}
|
||||
|
||||
if a[i].Prefix.String() != b[i].Prefix.String() {
|
||||
return false
|
||||
}
|
||||
|
||||
if a[i].Flags != b[i].Flags {
|
||||
return false
|
||||
}
|
||||
|
||||
// we don't compare the lifetimes because they are not always same
|
||||
if a[i].Scope != b[i].Scope {
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -1,8 +1,21 @@
|
|||
import { cx } from "@/cva.config";
|
||||
import { NetworkState } from "../hooks/stores";
|
||||
import { LifeTimeLabel } from "../routes/devices.$id.settings.network";
|
||||
|
||||
import { GridCard } from "./Card";
|
||||
|
||||
export function FlagLabel({ flag, className }: { flag: string, className?: string }) {
|
||||
const classes = cx(
|
||||
"ml-2 rounded-sm bg-red-500 px-2 py-1 text-[10px] font-medium leading-none text-white dark:border",
|
||||
"bg-red-500 text-white dark:border-red-700 dark:bg-red-800 dark:text-red-50",
|
||||
className,
|
||||
);
|
||||
|
||||
return <span className={classes}>
|
||||
{flag}
|
||||
</span>
|
||||
}
|
||||
|
||||
export default function Ipv6NetworkCard({
|
||||
networkState,
|
||||
}: {
|
||||
|
|
@ -49,7 +62,13 @@ export default function Ipv6NetworkCard({
|
|||
<span className="text-sm text-slate-600 dark:text-slate-400">
|
||||
Address
|
||||
</span>
|
||||
<span className="text-sm font-medium">{addr.address}</span>
|
||||
<span className="text-sm font-medium flex">
|
||||
<span className="flex-1">{addr.address}</span>
|
||||
<span className="text-sm font-medium flex gap-x-1">
|
||||
{addr.flag_deprecated ? <FlagLabel flag="Deprecated" /> : null}
|
||||
{addr.flag_dad_failed ? <FlagLabel flag="DAD Failed" /> : null}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{addr.valid_lifetime && (
|
||||
|
|
|
|||
|
|
@ -699,6 +699,15 @@ export interface IPv6Address {
|
|||
valid_lifetime: string;
|
||||
preferred_lifetime: string;
|
||||
scope: string;
|
||||
flags: number;
|
||||
flag_secondary?: boolean;
|
||||
flag_permanent?: boolean;
|
||||
flag_temporary?: boolean;
|
||||
flag_stable_privacy?: boolean;
|
||||
flag_deprecated?: boolean;
|
||||
flag_optimistic?: boolean;
|
||||
flag_dad_failed?: boolean;
|
||||
flag_tentative?: boolean;
|
||||
}
|
||||
|
||||
export interface NetworkState {
|
||||
|
|
|
|||
Loading…
Reference in New Issue